vendor: golang.org/x/net v0.56.0

full diff: https://github.com/golang/net/compare/v0.55.0...v0.56.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn
2026-06-19 17:12:50 +02:00
parent a271da13ea
commit 04c24b93df
10 changed files with 231 additions and 249 deletions
+1 -1
View File
@@ -227,7 +227,7 @@ require (
go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.opentelemetry.io/proto/otlp v1.10.0 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect
go.yaml.in/yaml/v4 v4.0.0-rc.4 // indirect go.yaml.in/yaml/v4 v4.0.0-rc.4 // indirect
golang.org/x/net v0.55.0 // indirect golang.org/x/net v0.56.0 // indirect
golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect
golang.org/x/time v0.15.0 // indirect golang.org/x/time v0.15.0 // indirect
golang.org/x/tools v0.45.0 // indirect golang.org/x/tools v0.45.0 // indirect
+2 -2
View File
@@ -654,8 +654,8 @@ golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
+2 -3
View File
@@ -2156,9 +2156,8 @@ var entity = map[string]rune{
// HTML entities that are two unicode codepoints. // HTML entities that are two unicode codepoints.
var entity2 = map[string][2]rune{ var entity2 = map[string][2]rune{
// TODO(nigeltao): Handle replacements that are wider than their names. "nLt;": {'\u226A', '\u20D2'},
// "nLt;": {'\u226A', '\u20D2'}, "nGt;": {'\u226B', '\u20D2'},
// "nGt;": {'\u226B', '\u20D2'},
"NotEqualTilde;": {'\u2242', '\u0338'}, "NotEqualTilde;": {'\u2242', '\u0338'},
"NotGreaterFullEqual;": {'\u2267', '\u0338'}, "NotGreaterFullEqual;": {'\u2267', '\u0338'},
"NotGreaterGreater;": {'\u226B', '\u0338'}, "NotGreaterGreater;": {'\u226B', '\u0338'},
+92 -52
View File
@@ -6,6 +6,7 @@ package html
import ( import (
"bytes" "bytes"
"slices"
"strings" "strings"
"unicode/utf8" "unicode/utf8"
) )
@@ -50,25 +51,24 @@ var replacementTable = [...]rune{
// 0x0D->'\u000D' is a no-op. // 0x0D->'\u000D' is a no-op.
} }
// unescapeEntity reads an entity like "&lt;" from b[src:] and writes the // unescapeEntity attempts to consume a character reference from s[src:],
// corresponding "<" to b[dst:], returning the incremented dst and src cursors. // returning the rune, potential second rune, and number of bytes consumed
// Precondition: b[src] == '&' && dst <= src. // (which indicates the length of the character reference). It is assumed that
// attribute should be true if parsing an attribute value. // the first byte of s is '&'. attribute should be true if parsing an attribute
func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) { // value.
func unescapeEntity(s []byte, attribute bool) (rune, rune, int) {
// https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference // https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference
// i starts at 1 because we already know that s[0] == '&'. // i starts at 1 because we already know that s[0] == '&'.
i, s := 1, b[src:] i := 1
if len(s) <= 1 { if len(s) <= 1 {
b[dst] = b[src] return '&', 0, 1
return dst + 1, src + 1
} }
if s[i] == '#' { if s[i] == '#' {
if len(s) <= 3 { // We need to have at least "&#.". if len(s) <= 2 { // We need to have at least "&#".
b[dst] = b[src] return '&', 0, 1
return dst + 1, src + 1
} }
i++ i++
c := s[i] c := s[i]
@@ -78,34 +78,43 @@ func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
i++ i++
} }
i0 := i
x := '\x00' x := '\x00'
for i < len(s) { for i < len(s) {
c = s[i] c = s[i]
i++ var d rune
var mult rune
if hex { if hex {
mult = 16
if '0' <= c && c <= '9' { if '0' <= c && c <= '9' {
x = 16*x + rune(c) - '0' d = rune(c) - '0'
continue
} else if 'a' <= c && c <= 'f' { } else if 'a' <= c && c <= 'f' {
x = 16*x + rune(c) - 'a' + 10 d = rune(c) - 'a' + 10
continue
} else if 'A' <= c && c <= 'F' { } else if 'A' <= c && c <= 'F' {
x = 16*x + rune(c) - 'A' + 10 d = rune(c) - 'A' + 10
continue } else {
break
}
} else {
mult = 10
if '0' <= c && c <= '9' {
d = rune(c) - '0'
} else {
break
} }
} else if '0' <= c && c <= '9' {
x = 10*x + rune(c) - '0'
continue
} }
if c != ';' { if x <= 0x10FFFF {
i-- x = mult*x + d
} }
break i++
} }
if i <= 3 { // No characters matched. if i == i0 { // No characters matched.
b[dst] = b[src] return '&', 0, 1
return dst + 1, src + 1 }
if i < len(s) && s[i] == ';' {
i++
} }
if 0x80 <= x && x <= 0x9F { if 0x80 <= x && x <= 0x9F {
@@ -116,7 +125,7 @@ func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
x = '\uFFFD' x = '\uFFFD'
} }
return dst + utf8.EncodeRune(b[dst:], x), src + i return x, 0, i
} }
// Consume the maximum number of characters possible, with the // Consume the maximum number of characters possible, with the
@@ -141,10 +150,9 @@ func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
} else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' { } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' {
// No-op. // No-op.
} else if x := entity[entityName]; x != 0 { } else if x := entity[entityName]; x != 0 {
return dst + utf8.EncodeRune(b[dst:], x), src + i return x, 0, i
} else if x := entity2[entityName]; x[0] != 0 { } else if x := entity2[entityName]; x[0] != 0 {
dst1 := dst + utf8.EncodeRune(b[dst:], x[0]) return x[0], x[1], i
return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i
} else if !attribute { } else if !attribute {
maxLen := len(entityName) - 1 maxLen := len(entityName) - 1
if maxLen > longestEntityWithoutSemicolon { if maxLen > longestEntityWithoutSemicolon {
@@ -152,35 +160,67 @@ func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
} }
for j := maxLen; j > 1; j-- { for j := maxLen; j > 1; j-- {
if x := entity[entityName[:j]]; x != 0 { if x := entity[entityName[:j]]; x != 0 {
return dst + utf8.EncodeRune(b[dst:], x), src + j + 1 return x, 0, j + 1
} }
} }
} }
dst1, src1 = dst+i, src+i return '&', 0, 1
copy(b[dst:dst1], b[src:src1])
return dst1, src1
} }
// unescape unescapes b's entities in-place, so that "a&lt;b" becomes "a<b". // unescape unescapes b's entites, so that "a&lt;b" becomes "a<b". It attempts
// attribute should be true if parsing an attribute value. // to do so in place, but if the unescaped value is longer than the input it
// allocates a new slice. attribute should be true if parsing an attribute
// value.
func unescape(b []byte, attribute bool) []byte { func unescape(b []byte, attribute bool) []byte {
for i, c := range b { firstAmp := slices.Index(b, '&')
if c == '&' { if firstAmp == -1 {
dst, src := unescapeEntity(b, i, i, attribute) return b
for src < len(b) {
c := b[src]
if c == '&' {
dst, src = unescapeEntity(b, dst, src, attribute)
} else {
b[dst] = c
dst, src = dst+1, src+1
}
}
return b[0:dst]
}
} }
return b
out := b[:firstAmp]
src := firstAmp
reusingB := true
for src < len(b) {
if b[src] != '&' {
out = append(out, b[src])
src++
continue
}
r1, r2, entityNameLen := unescapeEntity(b[src:], attribute)
if entityNameLen == 1 && r1 == '&' {
// Not an entity
out = append(out, '&')
src++
continue
}
// Compute replacement length
replLen := utf8.RuneLen(r1)
if r2 != 0 {
replLen += utf8.RuneLen(r2)
}
// If the name of the entity is shorter than the width of the
// replacement runes then we need to expand the output slice to
// fit the replacement.
if replLen > entityNameLen {
if reusingB {
out = slices.Clone(out)
reusingB = false
}
out = slices.Grow(out, replLen)
}
out = utf8.AppendRune(out, r1)
if r2 != 0 {
out = utf8.AppendRune(out, r2)
}
src += entityNameLen
}
return out
} }
// lower lower-cases the A-Z bytes in b in-place, so that "aBc" becomes "abc". // lower lower-cases the A-Z bytes in b in-place, so that "aBc" becomes "abc".
+1 -1
View File
@@ -23,7 +23,7 @@ func adjustForeignAttributes(aa []Attribute) {
} }
switch a.Key { switch a.Key {
case "xlink:actuate", "xlink:arcrole", "xlink:href", "xlink:role", "xlink:show", case "xlink:actuate", "xlink:arcrole", "xlink:href", "xlink:role", "xlink:show",
"xlink:title", "xlink:type", "xml:base", "xml:lang", "xml:space", "xmlns:xlink": "xlink:title", "xlink:type", "xml:lang", "xml:space", "xmlns:xlink":
j := strings.Index(a.Key, ":") j := strings.Index(a.Key, ":")
aa[i].Namespace = a.Key[:j] aa[i].Namespace = a.Key[:j]
aa[i].Key = a.Key[j+1:] aa[i].Key = a.Key[j+1:]
+67 -182
View File
@@ -63,7 +63,7 @@ func (p *parser) top() *Node {
// Stop tags for use in popUntil. These come from section 12.2.4.2. // Stop tags for use in popUntil. These come from section 12.2.4.2.
var ( var (
defaultScopeStopTags = map[string][]a.Atom{ defaultScopeStopTags = map[string][]a.Atom{
"": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template}, "": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template, a.Select},
"math": {a.AnnotationXml, a.Mi, a.Mn, a.Mo, a.Ms, a.Mtext}, "math": {a.AnnotationXml, a.Mi, a.Mn, a.Mo, a.Ms, a.Mtext},
"svg": {a.Desc, a.ForeignObject, a.Title}, "svg": {a.Desc, a.ForeignObject, a.Title},
} }
@@ -78,7 +78,6 @@ const (
tableScope tableScope
tableRowScope tableRowScope
tableBodyScope tableBodyScope
selectScope
) )
// popUntil pops the stack of open elements at the highest element whose tag // popUntil pops the stack of open elements at the highest element whose tag
@@ -133,10 +132,6 @@ func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int {
if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template { if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template {
return -1 return -1
} }
case selectScope:
if tagAtom != a.Optgroup && tagAtom != a.Option {
return -1
}
default: default:
panic(fmt.Sprintf("html: internal error: indexOfElementInScope unknown scope: %d", s)) panic(fmt.Sprintf("html: internal error: indexOfElementInScope unknown scope: %d", s))
} }
@@ -460,21 +455,6 @@ func (p *parser) resetInsertionMode() {
} }
switch n.DataAtom { switch n.DataAtom {
case a.Select:
if !last {
for ancestor, first := n, p.oe[0]; ancestor != first; {
ancestor = p.oe[p.oe.index(ancestor)-1]
switch ancestor.DataAtom {
case a.Template:
p.im = inSelectIM
return
case a.Table:
p.im = inSelectInTableIM
return
}
}
}
p.im = inSelectIM
case a.Td, a.Th: case a.Td, a.Th:
// TODO: remove this divergence from the HTML5 spec. // TODO: remove this divergence from the HTML5 spec.
// //
@@ -1002,7 +982,10 @@ func inBodyIM(p *parser) bool {
p.popUntil(buttonScope, a.P) p.popUntil(buttonScope, a.P)
p.addElement() p.addElement()
case a.Button: case a.Button:
p.popUntil(defaultScope, a.Button) if p.elementInScope(defaultScope, a.Button) {
p.generateImpliedEndTags()
p.popUntil(defaultScope, a.Button)
}
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
p.addElement() p.addElement()
p.framesetOK = false p.framesetOK = false
@@ -1040,7 +1023,18 @@ func inBodyIM(p *parser) bool {
p.framesetOK = false p.framesetOK = false
p.im = inTableIM p.im = inTableIM
return true return true
case a.Area, a.Br, a.Embed, a.Img, a.Input, a.Keygen, a.Wbr: case a.Area, a.Br, a.Embed, a.Img, a.Keygen, a.Wbr:
p.reconstructActiveFormattingElements()
p.addElement()
p.oe.pop()
p.acknowledgeSelfClosingTag()
p.framesetOK = false
case a.Input:
if p.fragment && p.context.DataAtom == a.Select {
// Ignore the token.
return true
}
p.popUntil(defaultScope, a.Select)
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
p.addElement() p.addElement()
p.oe.pop() p.oe.pop()
@@ -1061,7 +1055,13 @@ func inBodyIM(p *parser) bool {
p.oe.pop() p.oe.pop()
p.acknowledgeSelfClosingTag() p.acknowledgeSelfClosingTag()
case a.Hr: case a.Hr:
p.popUntil(buttonScope, a.P) if p.elementInScope(buttonScope, a.P) {
p.generateImpliedEndTags("p")
p.popUntil(defaultScope, a.P)
}
if p.elementInScope(defaultScope, a.Select) {
p.generateImpliedEndTags()
}
p.addElement() p.addElement()
p.oe.pop() p.oe.pop()
p.acknowledgeSelfClosingTag() p.acknowledgeSelfClosingTag()
@@ -1095,13 +1095,30 @@ func inBodyIM(p *parser) bool {
// Don't let the tokenizer go into raw text mode when scripting is disabled. // Don't let the tokenizer go into raw text mode when scripting is disabled.
p.tokenizer.NextIsNotRawText() p.tokenizer.NextIsNotRawText()
case a.Select: case a.Select:
if p.fragment && p.context.DataAtom == a.Select {
// Ignore the token.
return true
} else if p.popUntil(defaultScope, a.Select) {
return true
}
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
p.addElement() p.addElement()
p.framesetOK = false p.framesetOK = false
p.im = inSelectIM
return true return true
case a.Optgroup, a.Option: case a.Option:
if p.top().DataAtom == a.Option { if p.elementInScope(defaultScope, a.Select) {
p.generateImpliedEndTags("optgroup")
// If oe has option element in scope, parse error?
} else if p.top().DataAtom == a.Option {
p.oe.pop()
}
p.reconstructActiveFormattingElements()
p.addElement()
case a.Optgroup:
if p.elementInScope(defaultScope, a.Select) {
p.generateImpliedEndTags()
// If oe has option or optgroup element in scope, parse error?
} else if p.top().DataAtom == a.Option {
p.oe.pop() p.oe.pop()
} }
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
@@ -1149,7 +1166,12 @@ func inBodyIM(p *parser) bool {
return false return false
} }
return true return true
case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dialog, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Main, a.Menu, a.Nav, a.Ol, a.Pre, a.Search, a.Section, a.Summary, a.Ul: case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dialog, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Main, a.Menu, a.Nav, a.Ol, a.Pre, a.Search, a.Section, a.Select, a.Summary, a.Ul:
if !p.elementInScope(defaultScope, p.tok.DataAtom) {
// Ignore the token.
return true
}
p.generateImpliedEndTags()
p.popUntil(defaultScope, p.tok.DataAtom) p.popUntil(defaultScope, p.tok.DataAtom)
case a.Form: case a.Form:
if p.oe.contains(a.Template) { if p.oe.contains(a.Template) {
@@ -1488,17 +1510,6 @@ func inTableIM(p *parser) bool {
} }
p.addElement() p.addElement()
p.form = p.oe.pop() p.form = p.oe.pop()
case a.Select:
p.reconstructActiveFormattingElements()
switch p.top().DataAtom {
case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
p.fosterParenting = true
}
p.addElement()
p.fosterParenting = false
p.framesetOK = false
p.im = inSelectInTableIM
return true
} }
case EndTagToken: case EndTagToken:
switch p.tok.DataAtom { switch p.tok.DataAtom {
@@ -1547,12 +1558,6 @@ func inCaptionIM(p *parser) bool {
p.clearActiveFormattingElements() p.clearActiveFormattingElements()
p.im = inTableIM p.im = inTableIM
return false return false
case a.Select:
p.reconstructActiveFormattingElements()
p.addElement()
p.framesetOK = false
p.im = inSelectInTableIM
return true
} }
case EndTagToken: case EndTagToken:
switch p.tok.DataAtom { switch p.tok.DataAtom {
@@ -1762,12 +1767,6 @@ func inCellIM(p *parser) bool {
} }
// Ignore the token. // Ignore the token.
return true return true
case a.Select:
p.reconstructActiveFormattingElements()
p.addElement()
p.framesetOK = false
p.im = inSelectInTableIM
return true
} }
case EndTagToken: case EndTagToken:
switch p.tok.DataAtom { switch p.tok.DataAtom {
@@ -1798,118 +1797,6 @@ func inCellIM(p *parser) bool {
return inBodyIM(p) return inBodyIM(p)
} }
// Section 12.2.6.4.16.
func inSelectIM(p *parser) bool {
switch p.tok.Type {
case TextToken:
p.addText(strings.Replace(p.tok.Data, "\x00", "", -1))
case StartTagToken:
switch p.tok.DataAtom {
case a.Html:
return inBodyIM(p)
case a.Option:
if p.top().DataAtom == a.Option {
p.oe.pop()
}
p.addElement()
case a.Optgroup:
if p.top().DataAtom == a.Option {
p.oe.pop()
}
if p.top().DataAtom == a.Optgroup {
p.oe.pop()
}
p.addElement()
case a.Select:
if !p.popUntil(selectScope, a.Select) {
// Ignore the token.
return true
}
p.resetInsertionMode()
case a.Input, a.Keygen, a.Textarea:
if p.elementInScope(selectScope, a.Select) {
p.parseImpliedToken(EndTagToken, a.Select, a.Select.String())
return false
}
// In order to properly ignore <textarea>, we need to change the tokenizer mode.
p.tokenizer.NextIsNotRawText()
// Ignore the token.
return true
case a.Script, a.Template:
return inHeadIM(p)
case a.Iframe, a.Noembed, a.Noframes, a.Noscript, a.Plaintext, a.Style, a.Title, a.Xmp:
// Don't let the tokenizer go into raw text mode when there are raw tags
// to be ignored. These tags should be ignored from the tokenizer
// properly.
p.tokenizer.NextIsNotRawText()
// Ignore the token.
return true
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Option:
if p.top().DataAtom == a.Option {
p.oe.pop()
}
case a.Optgroup:
i := len(p.oe) - 1
if p.oe[i].DataAtom == a.Option {
i--
}
if p.oe[i].DataAtom == a.Optgroup {
p.oe = p.oe[:i]
}
case a.Select:
if !p.popUntil(selectScope, a.Select) {
// Ignore the token.
return true
}
p.resetInsertionMode()
case a.Template:
return inHeadIM(p)
}
case CommentToken:
p.addChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
case DoctypeToken:
// Ignore the token.
return true
case ErrorToken:
return inBodyIM(p)
}
return true
}
// Section 12.2.6.4.17.
func inSelectInTableIM(p *parser) bool {
switch p.tok.Type {
case StartTagToken, EndTagToken:
switch p.tok.DataAtom {
case a.Caption, a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr, a.Td, a.Th:
if p.tok.Type == EndTagToken && !p.elementInScope(tableScope, p.tok.DataAtom) {
// Ignore the token.
return true
}
// This is like p.popUntil(selectScope, a.Select), but it also
// matches <math select>, not just <select>. Matching the MathML
// tag is arguably incorrect (conceptually), but it mimics what
// Chromium does.
for i := len(p.oe) - 1; i >= 0; i-- {
if n := p.oe[i]; n.DataAtom == a.Select {
p.oe = p.oe[:i]
break
}
}
p.resetInsertionMode()
return false
}
}
return inSelectIM(p)
}
// Section 12.2.6.4.18. // Section 12.2.6.4.18.
func inTemplateIM(p *parser) bool { func inTemplateIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
@@ -2174,7 +2061,7 @@ func ignoreTheRemainingTokens(p *parser) bool {
const whitespaceOrNUL = whitespace + "\x00" const whitespaceOrNUL = whitespace + "\x00"
// Section 12.2.6.5 // Section 13.2.6.5
func parseForeignContent(p *parser) bool { func parseForeignContent(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case TextToken: case TextToken:
@@ -2189,28 +2076,26 @@ func parseForeignContent(p *parser) bool {
Data: p.tok.Data, Data: p.tok.Data,
}) })
case StartTagToken: case StartTagToken:
if !p.fragment { b := breakout[p.tok.Data]
b := breakout[p.tok.Data] if p.tok.DataAtom == a.Font {
if p.tok.DataAtom == a.Font { loop:
loop: for _, attr := range p.tok.Attr {
for _, attr := range p.tok.Attr { switch attr.Key {
switch attr.Key { case "color", "face", "size":
case "color", "face", "size": b = true
b = true break loop
break loop
}
} }
} }
if b { }
for i := len(p.oe) - 1; i >= 0; i-- { if b {
n := p.oe[i] for i := len(p.oe) - 1; i >= 0; i-- {
if n.Namespace == "" || htmlIntegrationPoint(n) || mathMLTextIntegrationPoint(n) { n := p.oe[i]
p.oe = p.oe[:i+1] if n.Namespace == "" || htmlIntegrationPoint(n) || mathMLTextIntegrationPoint(n) {
break p.oe = p.oe[:i+1]
} break
} }
return false
} }
return p.im(p)
} }
current := p.adjustedCurrentNode() current := p.adjustedCurrentNode()
switch current.Namespace { switch current.Namespace {
+36 -5
View File
@@ -704,7 +704,11 @@ func (z *Tokenizer) readMarkupDeclaration() TokenType {
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
c[i] = z.readByte() c[i] = z.readByte()
if z.err != nil { if z.err != nil {
// bogus comment
z.data.end = z.raw.end z.data.end = z.raw.end
if i == 1 && c[0] == '>' {
z.data.end--
}
return CommentToken return CommentToken
} }
} }
@@ -732,6 +736,13 @@ func (z *Tokenizer) readDoctype() bool {
for i := 0; i < len(s); i++ { for i := 0; i < len(s); i++ {
c := z.readByte() c := z.readByte()
if z.err != nil { if z.err != nil {
if z.err == io.EOF {
// Back up to read the fragment of "DOCTYPE" again, reset
// z.err to signal EOF on the next call
z.raw.end = z.data.start
z.err = nil
return false
}
z.data.end = z.raw.end z.data.end = z.raw.end
return false return false
} }
@@ -757,6 +768,13 @@ func (z *Tokenizer) readCDATA() bool {
for i := 0; i < len(s); i++ { for i := 0; i < len(s); i++ {
c := z.readByte() c := z.readByte()
if z.err != nil { if z.err != nil {
if z.err == io.EOF {
// Back up to read the fragment of "[CDATA[" again, reset
// z.err to signal EOF on the next call
z.raw.end = z.data.start
z.err = nil
return false
}
z.data.end = z.raw.end z.data.end = z.raw.end
return false return false
} }
@@ -883,7 +901,7 @@ func (z *Tokenizer) readTag(saveAttr bool) {
z.readTagAttrKey() z.readTagAttrKey()
z.readTagAttrVal() z.readTagAttrVal()
// Save pendingAttr if saveAttr and that attribute has a non-empty key, and the key hasn't been seen before. // Save pendingAttr if saveAttr and that attribute has a non-empty key, and the key hasn't been seen before.
key := strings.ToLower(string(z.buf[z.pendingAttr[0].start:z.pendingAttr[0].end])) key := string(lower(bytes.Clone(z.buf[z.pendingAttr[0].start:z.pendingAttr[0].end])))
if saveAttr && z.pendingAttr[0].start != z.pendingAttr[0].end && !z.attrNames[key] { if saveAttr && z.pendingAttr[0].start != z.pendingAttr[0].end && !z.attrNames[key] {
z.attr = append(z.attr, z.pendingAttr) z.attr = append(z.attr, z.pendingAttr)
z.attrNames[key] = true z.attrNames[key] = true
@@ -1206,7 +1224,7 @@ func (z *Tokenizer) TagName() (name []byte, hasAttr bool) {
if z.data.start < z.data.end { if z.data.start < z.data.end {
switch z.tt { switch z.tt {
case StartTagToken, EndTagToken, SelfClosingTagToken: case StartTagToken, EndTagToken, SelfClosingTagToken:
s := z.buf[z.data.start:z.data.end] s := bytes.ReplaceAll(z.buf[z.data.start:z.data.end], nul, replacement)
z.data.start = z.raw.end z.data.start = z.raw.end
z.data.end = z.raw.end z.data.end = z.raw.end
return lower(s), z.nAttrReturned < len(z.attr) return lower(s), z.nAttrReturned < len(z.attr)
@@ -1224,8 +1242,8 @@ func (z *Tokenizer) TagAttr() (key, val []byte, moreAttr bool) {
case StartTagToken, SelfClosingTagToken: case StartTagToken, SelfClosingTagToken:
x := z.attr[z.nAttrReturned] x := z.attr[z.nAttrReturned]
z.nAttrReturned++ z.nAttrReturned++
key = z.buf[x[0].start:x[0].end] key = bytes.ReplaceAll(z.buf[x[0].start:x[0].end], nul, replacement)
val = z.buf[x[1].start:x[1].end] val = bytes.ReplaceAll(z.buf[x[1].start:x[1].end], nul, replacement)
return lower(key), unescape(convertNewlines(val), true), z.nAttrReturned < len(z.attr) return lower(key), unescape(convertNewlines(val), true), z.nAttrReturned < len(z.attr)
} }
} }
@@ -1282,9 +1300,22 @@ func NewTokenizerFragment(r io.Reader, contextTag string) *Tokenizer {
attrNames: make(map[string]bool), attrNames: make(map[string]bool),
} }
if contextTag != "" { if contextTag != "" {
// Per the "Parsing HTML Fragments" portion of the spec:
// For performance reasons, an implementation that does not report errors
// and that uses the actual state machine described in this specification
// directly could use the PLAINTEXT state instead of the RAWTEXT and script
// data states where those are mentioned in the list above. Except for
// rules regarding parse errors, they are equivalent, since there is no
// appropriate end tag token in the fragment case, yet they involve far
// fewer state transitions.
//
// As such we just set everything to plaintext, which makes some complex parsing
// cases somewhat simpler.
switch s := strings.ToLower(contextTag); s { switch s := strings.ToLower(contextTag); s {
case "iframe", "noembed", "noframes", "noscript", "plaintext", "script", "style", "title", "textarea", "xmp": case "title", "textarea":
z.rawTag = s z.rawTag = s
case "style", "xmp", "iframe", "noembed", "noframes", "script", "noscript", "plaintext":
z.rawTag = "plaintext"
} }
} }
return z return z
+16
View File
@@ -10,9 +10,11 @@ package http2
import ( import (
"context" "context"
"crypto/tls"
"errors" "errors"
"net" "net"
"net/http" "net/http"
"slices"
"sync" "sync"
"time" "time"
) )
@@ -44,6 +46,20 @@ func configureServer(s *http.Server, conf *Server) error {
h2.IdleTimeout = h1.ReadTimeout h2.IdleTimeout = h1.ReadTimeout
} }
} }
// Register h2 and http/1.1 ALPN protocols on s.TLSConfig, matching
// the pre-wrapping implementation in server.go, so that TLS listeners
// built from s.TLSConfig still negotiate HTTP/2.
if s.TLSConfig == nil {
s.TLSConfig = new(tls.Config)
}
if !slices.Contains(s.TLSConfig.NextProtos, NextProtoTLS) {
s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, NextProtoTLS)
}
if !slices.Contains(s.TLSConfig.NextProtos, "http/1.1") {
s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "http/1.1")
}
conf.state = &serverInternalState{ conf.state = &serverInternalState{
s1: s, s1: s,
} }
+13 -2
View File
@@ -22,8 +22,8 @@ import (
) )
func configureTransport(t1 *http.Transport) error { func configureTransport(t1 *http.Transport) error {
// ConfigureTransport is a no-op: The http.Transport already supports HTTP/2. _, err := configureTransports(t1)
return nil return err
} }
func configureTransports(t1 *http.Transport) (*Transport, error) { func configureTransports(t1 *http.Transport) (*Transport, error) {
@@ -31,6 +31,17 @@ func configureTransports(t1 *http.Transport) (*Transport, error) {
// linked to the http.Transport's. // linked to the http.Transport's.
tr2 := &Transport{} tr2 := &Transport{}
tr2.configure(t1) tr2.configure(t1)
// Enable HTTP/2 on the transport, as the pre-wrapping implementation did:
// net/http does not auto-enable it for a transport with a custom
// TLSClientConfig or dialer.
if t1.TLSClientConfig == nil {
t1.TLSClientConfig = &tls.Config{}
}
if t1.Protocols == nil {
t1.Protocols = new(http.Protocols)
t1.Protocols.SetHTTP1(true)
}
t1.Protocols.SetHTTP2(true)
return tr2, nil return tr2, nil
} }
+1 -1
View File
@@ -1340,7 +1340,7 @@ golang.org/x/mod/internal/lazyregexp
golang.org/x/mod/module golang.org/x/mod/module
golang.org/x/mod/semver golang.org/x/mod/semver
golang.org/x/mod/sumdb/note golang.org/x/mod/sumdb/note
# golang.org/x/net v0.55.0 # golang.org/x/net v0.56.0
## explicit; go 1.25.0 ## explicit; go 1.25.0
golang.org/x/net/html golang.org/x/net/html
golang.org/x/net/html/atom golang.org/x/net/html/atom