// Copyright 2011 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 templateimport ()// htmlNospaceEscaper escapes for inclusion in unquoted attribute values.func htmlNospaceEscaper( ...any) string { , := stringify(...)if == "" {returnfilterFailsafe }if == contentTypeHTML {returnhtmlReplacer(stripTags(), htmlNospaceNormReplacementTable, false) }returnhtmlReplacer(, htmlNospaceReplacementTable, false)}// attrEscaper escapes for inclusion in quoted attribute values.func attrEscaper( ...any) string { , := stringify(...)if == contentTypeHTML {returnhtmlReplacer(stripTags(), htmlNormReplacementTable, true) }returnhtmlReplacer(, htmlReplacementTable, true)}// rcdataEscaper escapes for inclusion in an RCDATA element body.func rcdataEscaper( ...any) string { , := stringify(...)if == contentTypeHTML {returnhtmlReplacer(, htmlNormReplacementTable, true) }returnhtmlReplacer(, htmlReplacementTable, true)}// htmlEscaper escapes for inclusion in HTML text.func htmlEscaper( ...any) string { , := stringify(...)if == contentTypeHTML {return }returnhtmlReplacer(, htmlReplacementTable, true)}// htmlReplacementTable contains the runes that need to be escaped// inside a quoted attribute value or in a text node.var htmlReplacementTable = []string{// https://www.w3.org/TR/html5/syntax.html#attribute-value-(unquoted)-state // U+0000 NULL Parse error. Append a U+FFFD REPLACEMENT // CHARACTER character to the current attribute's value. // " // and similarly // https://www.w3.org/TR/html5/syntax.html#before-attribute-value-state0: "\uFFFD",'"': """,'&': "&",'\'': "'",'+': "+",'<': "<",'>': ">",}// htmlNormReplacementTable is like htmlReplacementTable but without '&' to// avoid over-encoding existing entities.var htmlNormReplacementTable = []string{0: "\uFFFD",'"': """,'\'': "'",'+': "+",'<': "<",'>': ">",}// htmlNospaceReplacementTable contains the runes that need to be escaped// inside an unquoted attribute value.// The set of runes escaped is the union of the HTML specials and// those determined by running the JS below in browsers:// <div id=d></div>// <script>(function () {// var a = [], d = document.getElementById("d"), i, c, s;// for (i = 0; i < 0x10000; ++i) {//// c = String.fromCharCode(i);// d.innerHTML = "<span title=" + c + "lt" + c + "></span>"// s = d.getElementsByTagName("SPAN")[0];// if (!s || s.title !== c + "lt" + c) { a.push(i.toString(16)); }//// }// document.write(a.join(", "));// })()</script>var htmlNospaceReplacementTable = []string{0: "�",'\t': "	",'\n': " ",'\v': "",'\f': "",'\r': " ",' ': " ",'"': """,'&': "&",'\'': "'",'+': "+",'<': "<",'=': "=",'>': ">",// A parse error in the attribute value (unquoted) and // before attribute value states. // Treated as a quoting character by IE.'`': "`",}// htmlNospaceNormReplacementTable is like htmlNospaceReplacementTable but// without '&' to avoid over-encoding existing entities.var htmlNospaceNormReplacementTable = []string{0: "�",'\t': "	",'\n': " ",'\v': "",'\f': "",'\r': " ",' ': " ",'"': """,'\'': "'",'+': "+",'<': "<",'=': "=",'>': ">",// A parse error in the attribute value (unquoted) and // before attribute value states. // Treated as a quoting character by IE.'`': "`",}// htmlReplacer returns s with runes replaced according to replacementTable// and when badRunes is true, certain bad runes are allowed through unescaped.func htmlReplacer( string, []string, bool) string { , := 0, new(strings.Builder) , := rune(0), 0for := 0; < len(); += {// Cannot use 'for range s' because we need to preserve the width // of the runes in the input. If we see a decoding error, the input // width will not be utf8.Runelen(r) and we will overrun the buffer. , = utf8.DecodeRuneInString([:])ifint() < len() {if := []; len() != 0 {if == 0 { .Grow(len()) } .WriteString([:]) .WriteString() = + } } elseif {// No-op. // IE does not allow these ranges in unquoted attrs. } elseif0xfdd0 <= && <= 0xfdef || 0xfff0 <= && <= 0xffff {if == 0 { .Grow(len()) }fmt.Fprintf(, "%s&#x%x;", [:], ) = + } }if == 0 {return } .WriteString([:])return .String()}// stripTags takes a snippet of HTML and returns only the text content.// For example, `<b>¡Hi!</b> <script>...</script>` -> `¡Hi! `.func stripTags( string) string {varstrings.Builder , , , := []byte(), context{}, 0, true// Using the transition funcs helps us avoid mangling // `<div title="1>2">` or `I <3 Ponies!`.for != len() {if .delim == delimNone { := .state// Use RCDATA instead of parsing into JS or CSS styles.if .element != elementNone && !isInTag() { = stateRCDATA } , := transitionFunc[](, [:]) := + if .state == stateText || .state == stateRCDATA {// Emit text up to the start of the tag or comment. := if .state != .state {for := - 1; >= ; -- {if [] == '<' { = break } } } .Write([:]) } else { = false } , = , continue } := + bytes.IndexAny([:], delimEnds[.delim])if < {break }if .delim != delimSpaceOrTagEnd {// Consume any quote. ++ } , = context{state: stateTag, element: .element}, }if {return } elseif .state == stateText || .state == stateRCDATA { .Write([:]) }return .String()}// htmlNameFilter accepts valid parts of an HTML attribute or tag name or// a known-safe HTML attribute.func htmlNameFilter( ...any) string { , := stringify(...)if == contentTypeHTMLAttr {return }iflen() == 0 {// Avoid violation of structure preservation. // <input checked {{.K}}={{.V}}>. // Without this, if .K is empty then .V is the value of // checked, but otherwise .V is the value of the attribute // named .K.returnfilterFailsafe } = strings.ToLower()if := attrType(); != contentTypePlain {// TODO: Split attr and element name part filters so we can recognize known attributes.returnfilterFailsafe }for , := range {switch {case'0' <= && <= '9':case'a' <= && <= 'z':default:returnfilterFailsafe } }return}// commentEscaper returns the empty string regardless of input.// Comment content does not correspond to any parsed structure or// human-readable content, so the simplest and most secure policy is to drop// content interpolated into comments.// This approach is equally valid whether or not static comment content is// removed from the template.func commentEscaper( ...any) string {return""}
The pages are generated with Goldsv0.7.0-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.