// 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 ()// endsWithCSSKeyword reports whether b ends with an ident that// case-insensitively matches the lower-case kw.func endsWithCSSKeyword( []byte, string) bool { := len() - len()if < 0 {// Too short.returnfalse }if != 0 { , := utf8.DecodeLastRune([:])ifisCSSNmchar() {// Too long.returnfalse } }// Many CSS keywords, such as "!important" can have characters encoded, // but the URI production does not allow that according to // https://www.w3.org/TR/css3-syntax/#TOK-URI // This does not attempt to recognize encoded keywords. For example, // given "\75\72\6c" and "url" this return false.returnstring(bytes.ToLower([:])) == }// isCSSNmchar reports whether rune is allowed anywhere in a CSS identifier.func isCSSNmchar( rune) bool {// Based on the CSS3 nmchar production but ignores multi-rune escape // sequences. // https://www.w3.org/TR/css3-syntax/#SUBTOK-nmcharreturn'a' <= && <= 'z' ||'A' <= && <= 'Z' ||'0' <= && <= '9' || == '-' || == '_' ||// Non-ASCII cases below.0x80 <= && <= 0xd7ff ||0xe000 <= && <= 0xfffd ||0x10000 <= && <= 0x10ffff}// decodeCSS decodes CSS3 escapes given a sequence of stringchars.// If there is no change, it returns the input, otherwise it returns a slice// backed by a new array.// https://www.w3.org/TR/css3-syntax/#SUBTOK-stringchar defines stringchar.func decodeCSS( []byte) []byte { := bytes.IndexByte(, '\\')if == -1 {return }// The UTF-8 sequence for a codepoint is never longer than 1 + the // number hex digits need to represent that codepoint, so len(s) is an // upper bound on the output length. := make([]byte, 0, len())forlen() != 0 { := bytes.IndexByte(, '\\')if == -1 { = len() } , = append(, [:]...), [:]iflen() < 2 {break }// https://www.w3.org/TR/css3-syntax/#SUBTOK-escape // escape ::= unicode | '\' [#x20-#x7E#x80-#xD7FF#xE000-#xFFFD#x10000-#x10FFFF]ifisHex([1]) {// https://www.w3.org/TR/css3-syntax/#SUBTOK-unicode // unicode ::= '\' [0-9a-fA-F]{1,6} wc? := 2for < len() && < 7 && isHex([]) { ++ } := hexDecode([1:])if > unicode.MaxRune { , = /16, -1 } := utf8.EncodeRune([len():cap()], )// The optional space at the end allows a hex // sequence to be followed by a literal hex. // string(decodeCSS([]byte(`\A B`))) == "\nB" , = [:len()+], skipCSSSpace([:]) } else {// `\\` decodes to `\` and `\"` to `"`. , := utf8.DecodeRune([1:]) , = append(, [1:1+]...), [1+:] } }return}// isHex reports whether the given character is a hex digit.func isHex( byte) bool {return'0' <= && <= '9' || 'a' <= && <= 'f' || 'A' <= && <= 'F'}// hexDecode decodes a short hex digit sequence: "10" -> 16.func hexDecode( []byte) rune { := '\x00'for , := range { <<= 4switch {case'0' <= && <= '9': |= rune( - '0')case'a' <= && <= 'f': |= rune(-'a') + 10case'A' <= && <= 'F': |= rune(-'A') + 10default:panic(fmt.Sprintf("Bad hex digit in %q", )) } }return}// skipCSSSpace returns a suffix of c, skipping over a single space.func skipCSSSpace( []byte) []byte {iflen() == 0 {return }// wc ::= #x9 | #xA | #xC | #xD | #x20switch [0] {case'\t', '\n', '\f', ' ':return [1:]case'\r':// This differs from CSS3's wc production because it contains a // probable spec error whereby wc contains all the single byte // sequences in nl (newline) but not CRLF.iflen() >= 2 && [1] == '\n' {return [2:] }return [1:] }return}// isCSSSpace reports whether b is a CSS space char as defined in wc.func isCSSSpace( byte) bool {switch {case'\t', '\n', '\f', '\r', ' ':returntrue }returnfalse}// cssEscaper escapes HTML and CSS special characters using \<hex>+ escapes.func cssEscaper( ...any) string { , := stringify(...)varstrings.Builder , , := rune(0), 0, 0for := 0; < len(); += {// See comment in htmlEscaper. , = utf8.DecodeRuneInString([:])varstringswitch {caseint() < len(cssReplacementTable) && cssReplacementTable[] != "": = cssReplacementTable[]default:continue }if == 0 { .Grow(len()) } .WriteString([:]) .WriteString() = + if != `\\` && ( == len() || isHex([]) || isCSSSpace([])) { .WriteByte(' ') } }if == 0 {return } .WriteString([:])return .String()}var cssReplacementTable = []string{0: `\0`,'\t': `\9`,'\n': `\a`,'\f': `\c`,'\r': `\d`,// Encode HTML specials as hex so the output can be embedded // in HTML attributes without further encoding.'"': `\22`,'&': `\26`,'\'': `\27`,'(': `\28`,')': `\29`,'+': `\2b`,'/': `\2f`,':': `\3a`,';': `\3b`,'<': `\3c`,'>': `\3e`,'\\': `\\`,'{': `\7b`,'}': `\7d`,}var expressionBytes = []byte("expression")var mozBindingBytes = []byte("mozbinding")// cssValueFilter allows innocuous CSS values in the output including CSS// quantities (10px or 25%), ID or class literals (#foo, .bar), keyword values// (inherit, blue), and colors (#888).// It filters out unsafe values, such as those that affect token boundaries,// and anything that might execute scripts.func cssValueFilter( ...any) string { , := stringify(...)if == contentTypeCSS {return } , := decodeCSS([]byte()), make([]byte, 0, 64)// CSS3 error handling is specified as honoring string boundaries per // https://www.w3.org/TR/css3-syntax/#error-handling : // Malformed declarations. User agents must handle unexpected // tokens encountered while parsing a declaration by reading until // the end of the declaration, while observing the rules for // matching pairs of (), [], {}, "", and '', and correctly handling // escapes. For example, a malformed declaration may be missing a // property, colon (:) or value. // So we need to make sure that values do not have mismatched bracket // or quote characters to prevent the browser from restarting parsing // inside a string that might embed JavaScript source.for , := range {switch {case0, '"', '\'', '(', ')', '/', ';', '@', '[', '\\', ']', '`', '{', '}', '<', '>':returnfilterFailsafecase'-':// Disallow <!-- or -->. // -- should not appear in valid identifiers.if != 0 && [-1] == '-' {returnfilterFailsafe }default:if < utf8.RuneSelf && isCSSNmchar(rune()) { = append(, ) } } } = bytes.ToLower()ifbytes.Contains(, expressionBytes) || bytes.Contains(, mozBindingBytes) {returnfilterFailsafe }returnstring()}
The pages are generated with Goldsv0.6.9-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 @Go100and1 (reachable from the left QR code) to get the latest news of Golds.