Update to go1.24.0

This commit is contained in:
Vorapol Rinsatitnon
2025-02-14 12:42:07 +07:00
parent 25e497e367
commit bf266cebe6
3169 changed files with 236789 additions and 60275 deletions

View File

@@ -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
})

View File

@@ -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")
}

View File

@@ -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])
}

View File

@@ -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)
}

View File

@@ -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",

View File

@@ -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)
}

View File

@@ -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 {