Update to go1.24.0
This commit is contained in:
@@ -9,22 +9,16 @@ import "sync"
|
||||
// All entities that do not end with ';' are 6 or fewer bytes long.
|
||||
const longestEntityWithoutSemicolon = 6
|
||||
|
||||
// entityMaps returns entity and entity2.
|
||||
//
|
||||
// entity is a map from HTML entity names to their values. The semicolon matters:
|
||||
// https://html.spec.whatwg.org/multipage/named-characters.html
|
||||
// lists both "amp" and "amp;" as two separate entries.
|
||||
//
|
||||
// Note that the HTML5 list is larger than the HTML4 list at
|
||||
// http://www.w3.org/TR/html4/sgml/entities.html
|
||||
var entity map[string]rune
|
||||
|
||||
// HTML entities that are two unicode codepoints.
|
||||
var entity2 map[string][2]rune
|
||||
|
||||
// populateMapsOnce guards calling populateMaps.
|
||||
var populateMapsOnce sync.Once
|
||||
|
||||
// populateMaps populates entity and entity2.
|
||||
func populateMaps() {
|
||||
//
|
||||
// entity2 is a map of HTML entities to two unicode codepoints.
|
||||
var entityMaps = sync.OnceValues(func() (entity map[string]rune, entity2 map[string][2]rune) {
|
||||
entity = map[string]rune{
|
||||
"AElig;": '\U000000C6',
|
||||
"AMP;": '\U00000026',
|
||||
@@ -2262,4 +2256,6 @@ func populateMaps() {
|
||||
"vsupnE;": {'\u2ACC', '\uFE00'},
|
||||
"vsupne;": {'\u228B', '\uFE00'},
|
||||
}
|
||||
}
|
||||
|
||||
return entity, entity2
|
||||
})
|
||||
|
||||
@@ -9,11 +9,9 @@ import (
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func init() {
|
||||
UnescapeString("") // force load of entity maps
|
||||
}
|
||||
|
||||
func TestEntityLength(t *testing.T) {
|
||||
entity, entity2 := entityMaps()
|
||||
|
||||
if len(entity) == 0 || len(entity2) == 0 {
|
||||
t.Fatal("maps not loaded")
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ var replacementTable = [...]rune{
|
||||
// unescapeEntity reads an entity like "<" from b[src:] and writes the
|
||||
// corresponding "<" to b[dst:], returning the incremented dst and src cursors.
|
||||
// Precondition: b[src] == '&' && dst <= src.
|
||||
func unescapeEntity(b []byte, dst, src int) (dst1, src1 int) {
|
||||
func unescapeEntity(b []byte, dst, src int, entity map[string]rune, entity2 map[string][2]rune) (dst1, src1 int) {
|
||||
const attribute = false
|
||||
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference
|
||||
@@ -185,7 +185,6 @@ func EscapeString(s string) string {
|
||||
// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
|
||||
// always true.
|
||||
func UnescapeString(s string) string {
|
||||
populateMapsOnce.Do(populateMaps)
|
||||
i := strings.IndexByte(s, '&')
|
||||
|
||||
if i < 0 {
|
||||
@@ -193,7 +192,8 @@ func UnescapeString(s string) string {
|
||||
}
|
||||
|
||||
b := []byte(s)
|
||||
dst, src := unescapeEntity(b, i, i)
|
||||
entity, entity2 := entityMaps()
|
||||
dst, src := unescapeEntity(b, i, i, entity, entity2)
|
||||
for len(s[src:]) > 0 {
|
||||
if s[src] == '&' {
|
||||
i = 0
|
||||
@@ -208,7 +208,7 @@ func UnescapeString(s string) string {
|
||||
if i > 0 {
|
||||
copy(b[dst:], s[src:src+i])
|
||||
}
|
||||
dst, src = unescapeEntity(b, dst+i, src+i)
|
||||
dst, src = unescapeEntity(b, dst+i, src+i, entity, entity2)
|
||||
}
|
||||
return string(b[:dst])
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"html"
|
||||
"internal/godebug"
|
||||
"io"
|
||||
"maps"
|
||||
"regexp"
|
||||
"text/template"
|
||||
"text/template/parse"
|
||||
@@ -145,7 +146,7 @@ func (e *escaper) escape(c context, n parse.Node) context {
|
||||
return c
|
||||
case *parse.ContinueNode:
|
||||
c.n = n
|
||||
e.rangeContext.continues = append(e.rangeContext.breaks, c)
|
||||
e.rangeContext.continues = append(e.rangeContext.continues, c)
|
||||
return context{state: stateDead}
|
||||
case *parse.IfNode:
|
||||
return e.escapeBranch(c, &n.BranchNode, "if")
|
||||
@@ -588,22 +589,14 @@ func (e *escaper) escapeListConditionally(c context, n *parse.ListNode, filter f
|
||||
e1 := makeEscaper(e.ns)
|
||||
e1.rangeContext = e.rangeContext
|
||||
// Make type inferences available to f.
|
||||
for k, v := range e.output {
|
||||
e1.output[k] = v
|
||||
}
|
||||
maps.Copy(e1.output, e.output)
|
||||
c = e1.escapeList(c, n)
|
||||
ok := filter != nil && filter(&e1, c)
|
||||
if ok {
|
||||
// Copy inferences and edits from e1 back into e.
|
||||
for k, v := range e1.output {
|
||||
e.output[k] = v
|
||||
}
|
||||
for k, v := range e1.derived {
|
||||
e.derived[k] = v
|
||||
}
|
||||
for k, v := range e1.called {
|
||||
e.called[k] = v
|
||||
}
|
||||
maps.Copy(e.output, e1.output)
|
||||
maps.Copy(e.derived, e1.derived)
|
||||
maps.Copy(e.called, e1.called)
|
||||
for k, v := range e1.actionNodeEdits {
|
||||
e.editActionNode(k, v)
|
||||
}
|
||||
|
||||
@@ -1060,6 +1060,10 @@ func TestErrors(t *testing.T) {
|
||||
"{{range .Items}}<a{{if .X}}{{continue}}{{end}}>{{end}}",
|
||||
"z:1:29: at range loop continue: {{range}} branches end in different contexts",
|
||||
},
|
||||
{
|
||||
"{{range .Items}}{{if .X}}{{break}}{{end}}<a{{if .Y}}{{continue}}{{end}}>{{if .Z}}{{continue}}{{end}}{{end}}",
|
||||
"z:1:54: at range loop continue: {{range}} branches end in different contexts",
|
||||
},
|
||||
{
|
||||
"<a b=1 c={{.H}}",
|
||||
"z: ends in a non-text context: {stateAttr delimSpaceOrTagEnd",
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
@@ -144,6 +145,8 @@ func indirectToJSONMarshaler(a any) any {
|
||||
return v.Interface()
|
||||
}
|
||||
|
||||
var scriptTagRe = regexp.MustCompile("(?i)<(/?)script")
|
||||
|
||||
// jsValEscaper escapes its inputs to a JS Expression (section 11.14) that has
|
||||
// neither side-effects nor free variables outside (NaN, Infinity).
|
||||
func jsValEscaper(args ...any) string {
|
||||
@@ -181,9 +184,9 @@ func jsValEscaper(args ...any) string {
|
||||
// In particular we:
|
||||
// * replace "*/" comment end tokens with "* /", which does not
|
||||
// terminate the comment
|
||||
// * replace "</script" with "\x3C/script", and "<!--" with
|
||||
// "\x3C!--", which prevents confusing script block termination
|
||||
// semantics
|
||||
// * replace "<script" and "</script" with "\x3Cscript" and "\x3C/script"
|
||||
// (case insensitively), and "<!--" with "\x3C!--", which prevents
|
||||
// confusing script block termination semantics
|
||||
//
|
||||
// We also put a space before the comment so that if it is flush against
|
||||
// a division operator it is not turned into a line comment:
|
||||
@@ -192,8 +195,8 @@ func jsValEscaper(args ...any) string {
|
||||
// x//* error marshaling y:
|
||||
// second line of error message */null
|
||||
errStr := err.Error()
|
||||
errStr = string(scriptTagRe.ReplaceAll([]byte(errStr), []byte(`\x3C${1}script`)))
|
||||
errStr = strings.ReplaceAll(errStr, "*/", "* /")
|
||||
errStr = strings.ReplaceAll(errStr, "</script", `\x3C/script`)
|
||||
errStr = strings.ReplaceAll(errStr, "<!--", `\x3C!--`)
|
||||
return fmt.Sprintf(" /* %s */null ", errStr)
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ func TestNextJsCtx(t *testing.T) {
|
||||
type jsonErrType struct{}
|
||||
|
||||
func (e *jsonErrType) MarshalJSON() ([]byte, error) {
|
||||
return nil, errors.New("beep */ boop </script blip <!--")
|
||||
return nil, errors.New("a */ b <script c </script d <!-- e <sCrIpT f </sCrIpT")
|
||||
}
|
||||
|
||||
func TestJSValEscaper(t *testing.T) {
|
||||
@@ -160,7 +160,7 @@ func TestJSValEscaper(t *testing.T) {
|
||||
{"</script", `"\u003c/script"`, false},
|
||||
{"\U0001D11E", "\"\U0001D11E\"", false}, // or "\uD834\uDD1E"
|
||||
{nil, " null ", false},
|
||||
{&jsonErrType{}, " /* json: error calling MarshalJSON for type *template.jsonErrType: beep * / boop \\x3C/script blip \\x3C!-- */null ", true},
|
||||
{&jsonErrType{}, " /* json: error calling MarshalJSON for type *template.jsonErrType: a * / b \\x3Cscript c \\x3C/script d \\x3C!-- e \\x3Cscript f \\x3C/script */null ", true},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
Reference in New Issue
Block a user