Update module golang.org/x/net to v0.56.0

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This commit is contained in:
renovate[bot]
2026-06-10 18:08:35 +00:00
committed by GitHub
parent 0454af479f
commit 25cb9d7e4e
10 changed files with 231 additions and 249 deletions

2
go.mod
View File

@@ -69,7 +69,7 @@ require (
go.podman.io/image/v5 v5.40.0
go.podman.io/storage v1.63.0
golang.org/x/crypto v0.53.0
golang.org/x/net v0.55.0
golang.org/x/net v0.56.0
golang.org/x/sync v0.21.0
golang.org/x/sys v0.46.0
golang.org/x/term v0.44.0

4
go.sum
View File

@@ -475,8 +475,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
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/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=

View File

@@ -2156,9 +2156,8 @@ var entity = map[string]rune{
// HTML entities that are two unicode codepoints.
var entity2 = map[string][2]rune{
// TODO(nigeltao): Handle replacements that are wider than their names.
// "nLt;": {'\u226A', '\u20D2'},
// "nGt;": {'\u226B', '\u20D2'},
"nLt;": {'\u226A', '\u20D2'},
"nGt;": {'\u226B', '\u20D2'},
"NotEqualTilde;": {'\u2242', '\u0338'},
"NotGreaterFullEqual;": {'\u2267', '\u0338'},
"NotGreaterGreater;": {'\u226B', '\u0338'},

View File

@@ -6,6 +6,7 @@ package html
import (
"bytes"
"slices"
"strings"
"unicode/utf8"
)
@@ -50,25 +51,24 @@ var replacementTable = [...]rune{
// 0x0D->'\u000D' is a no-op.
}
// unescapeEntity reads an entity like "&lt;" from b[src:] and writes the
// corresponding "<" to b[dst:], returning the incremented dst and src cursors.
// Precondition: b[src] == '&' && dst <= src.
// attribute should be true if parsing an attribute value.
func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
// unescapeEntity attempts to consume a character reference from s[src:],
// returning the rune, potential second rune, and number of bytes consumed
// (which indicates the length of the character reference). It is assumed that
// the first byte of s is '&'. attribute should be true if parsing an attribute
// value.
func unescapeEntity(s []byte, attribute bool) (rune, rune, int) {
// https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference
// i starts at 1 because we already know that s[0] == '&'.
i, s := 1, b[src:]
i := 1
if len(s) <= 1 {
b[dst] = b[src]
return dst + 1, src + 1
return '&', 0, 1
}
if s[i] == '#' {
if len(s) <= 3 { // We need to have at least "&#.".
b[dst] = b[src]
return dst + 1, src + 1
if len(s) <= 2 { // We need to have at least "&#".
return '&', 0, 1
}
i++
c := s[i]
@@ -78,34 +78,43 @@ func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
i++
}
i0 := i
x := '\x00'
for i < len(s) {
c = s[i]
i++
var d rune
var mult rune
if hex {
mult = 16
if '0' <= c && c <= '9' {
x = 16*x + rune(c) - '0'
continue
d = rune(c) - '0'
} else if 'a' <= c && c <= 'f' {
x = 16*x + rune(c) - 'a' + 10
continue
d = rune(c) - 'a' + 10
} else if 'A' <= c && c <= 'F' {
x = 16*x + rune(c) - 'A' + 10
continue
d = rune(c) - 'A' + 10
} 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 != ';' {
i--
if x <= 0x10FFFF {
x = mult*x + d
}
break
i++
}
if i <= 3 { // No characters matched.
b[dst] = b[src]
return dst + 1, src + 1
if i == i0 { // No characters matched.
return '&', 0, 1
}
if i < len(s) && s[i] == ';' {
i++
}
if 0x80 <= x && x <= 0x9F {
@@ -116,7 +125,7 @@ func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
x = '\uFFFD'
}
return dst + utf8.EncodeRune(b[dst:], x), src + i
return x, 0, i
}
// 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] == '=' {
// No-op.
} 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 {
dst1 := dst + utf8.EncodeRune(b[dst:], x[0])
return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i
return x[0], x[1], i
} else if !attribute {
maxLen := len(entityName) - 1
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-- {
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
copy(b[dst:dst1], b[src:src1])
return dst1, src1
return '&', 0, 1
}
// unescape unescapes b's entities in-place, so that "a&lt;b" becomes "a<b".
// attribute should be true if parsing an attribute value.
// unescape unescapes b's entites, so that "a&lt;b" becomes "a<b". It attempts
// 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 {
for i, c := range b {
if c == '&' {
dst, src := unescapeEntity(b, i, i, attribute)
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]
}
firstAmp := slices.Index(b, '&')
if firstAmp == -1 {
return b
}
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".

View File

@@ -23,7 +23,7 @@ func adjustForeignAttributes(aa []Attribute) {
}
switch a.Key {
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, ":")
aa[i].Namespace = a.Key[:j]
aa[i].Key = a.Key[j+1:]

249
vendor/golang.org/x/net/html/parse.go generated vendored
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.
var (
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},
"svg": {a.Desc, a.ForeignObject, a.Title},
}
@@ -78,7 +78,6 @@ const (
tableScope
tableRowScope
tableBodyScope
selectScope
)
// 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 {
return -1
}
case selectScope:
if tagAtom != a.Optgroup && tagAtom != a.Option {
return -1
}
default:
panic(fmt.Sprintf("html: internal error: indexOfElementInScope unknown scope: %d", s))
}
@@ -460,21 +455,6 @@ func (p *parser) resetInsertionMode() {
}
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:
// TODO: remove this divergence from the HTML5 spec.
//
@@ -1002,7 +982,10 @@ func inBodyIM(p *parser) bool {
p.popUntil(buttonScope, a.P)
p.addElement()
case a.Button:
p.popUntil(defaultScope, a.Button)
if p.elementInScope(defaultScope, a.Button) {
p.generateImpliedEndTags()
p.popUntil(defaultScope, a.Button)
}
p.reconstructActiveFormattingElements()
p.addElement()
p.framesetOK = false
@@ -1040,7 +1023,18 @@ func inBodyIM(p *parser) bool {
p.framesetOK = false
p.im = inTableIM
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.addElement()
p.oe.pop()
@@ -1061,7 +1055,13 @@ func inBodyIM(p *parser) bool {
p.oe.pop()
p.acknowledgeSelfClosingTag()
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.oe.pop()
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.
p.tokenizer.NextIsNotRawText()
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.addElement()
p.framesetOK = false
p.im = inSelectIM
return true
case a.Optgroup, a.Option:
if p.top().DataAtom == a.Option {
case 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.reconstructActiveFormattingElements()
@@ -1149,7 +1166,12 @@ func inBodyIM(p *parser) bool {
return false
}
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)
case a.Form:
if p.oe.contains(a.Template) {
@@ -1488,17 +1510,6 @@ func inTableIM(p *parser) bool {
}
p.addElement()
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:
switch p.tok.DataAtom {
@@ -1547,12 +1558,6 @@ func inCaptionIM(p *parser) bool {
p.clearActiveFormattingElements()
p.im = inTableIM
return false
case a.Select:
p.reconstructActiveFormattingElements()
p.addElement()
p.framesetOK = false
p.im = inSelectInTableIM
return true
}
case EndTagToken:
switch p.tok.DataAtom {
@@ -1762,12 +1767,6 @@ func inCellIM(p *parser) bool {
}
// Ignore the token.
return true
case a.Select:
p.reconstructActiveFormattingElements()
p.addElement()
p.framesetOK = false
p.im = inSelectInTableIM
return true
}
case EndTagToken:
switch p.tok.DataAtom {
@@ -1798,118 +1797,6 @@ func inCellIM(p *parser) bool {
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.
func inTemplateIM(p *parser) bool {
switch p.tok.Type {
@@ -2174,7 +2061,7 @@ func ignoreTheRemainingTokens(p *parser) bool {
const whitespaceOrNUL = whitespace + "\x00"
// Section 12.2.6.5
// Section 13.2.6.5
func parseForeignContent(p *parser) bool {
switch p.tok.Type {
case TextToken:
@@ -2189,28 +2076,26 @@ func parseForeignContent(p *parser) bool {
Data: p.tok.Data,
})
case StartTagToken:
if !p.fragment {
b := breakout[p.tok.Data]
if p.tok.DataAtom == a.Font {
loop:
for _, attr := range p.tok.Attr {
switch attr.Key {
case "color", "face", "size":
b = true
break loop
}
b := breakout[p.tok.Data]
if p.tok.DataAtom == a.Font {
loop:
for _, attr := range p.tok.Attr {
switch attr.Key {
case "color", "face", "size":
b = true
break loop
}
}
if b {
for i := len(p.oe) - 1; i >= 0; i-- {
n := p.oe[i]
if n.Namespace == "" || htmlIntegrationPoint(n) || mathMLTextIntegrationPoint(n) {
p.oe = p.oe[:i+1]
break
}
}
if b {
for i := len(p.oe) - 1; i >= 0; i-- {
n := p.oe[i]
if n.Namespace == "" || htmlIntegrationPoint(n) || mathMLTextIntegrationPoint(n) {
p.oe = p.oe[:i+1]
break
}
return false
}
return p.im(p)
}
current := p.adjustedCurrentNode()
switch current.Namespace {

View File

@@ -704,7 +704,11 @@ func (z *Tokenizer) readMarkupDeclaration() TokenType {
for i := 0; i < 2; i++ {
c[i] = z.readByte()
if z.err != nil {
// bogus comment
z.data.end = z.raw.end
if i == 1 && c[0] == '>' {
z.data.end--
}
return CommentToken
}
}
@@ -732,6 +736,13 @@ func (z *Tokenizer) readDoctype() bool {
for i := 0; i < len(s); i++ {
c := z.readByte()
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
return false
}
@@ -757,6 +768,13 @@ func (z *Tokenizer) readCDATA() bool {
for i := 0; i < len(s); i++ {
c := z.readByte()
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
return false
}
@@ -883,7 +901,7 @@ func (z *Tokenizer) readTag(saveAttr bool) {
z.readTagAttrKey()
z.readTagAttrVal()
// 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] {
z.attr = append(z.attr, z.pendingAttr)
z.attrNames[key] = true
@@ -1206,7 +1224,7 @@ func (z *Tokenizer) TagName() (name []byte, hasAttr bool) {
if z.data.start < z.data.end {
switch z.tt {
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.end = z.raw.end
return lower(s), z.nAttrReturned < len(z.attr)
@@ -1224,8 +1242,8 @@ func (z *Tokenizer) TagAttr() (key, val []byte, moreAttr bool) {
case StartTagToken, SelfClosingTagToken:
x := z.attr[z.nAttrReturned]
z.nAttrReturned++
key = z.buf[x[0].start:x[0].end]
val = z.buf[x[1].start:x[1].end]
key = bytes.ReplaceAll(z.buf[x[0].start:x[0].end], nul, replacement)
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)
}
}
@@ -1282,9 +1300,22 @@ func NewTokenizerFragment(r io.Reader, contextTag string) *Tokenizer {
attrNames: make(map[string]bool),
}
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 {
case "iframe", "noembed", "noframes", "noscript", "plaintext", "script", "style", "title", "textarea", "xmp":
case "title", "textarea":
z.rawTag = s
case "style", "xmp", "iframe", "noembed", "noframes", "script", "noscript", "plaintext":
z.rawTag = "plaintext"
}
}
return z

View File

@@ -10,9 +10,11 @@ package http2
import (
"context"
"crypto/tls"
"errors"
"net"
"net/http"
"slices"
"sync"
"time"
)
@@ -44,6 +46,20 @@ func configureServer(s *http.Server, conf *Server) error {
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{
s1: s,
}

View File

@@ -22,8 +22,8 @@ import (
)
func configureTransport(t1 *http.Transport) error {
// ConfigureTransport is a no-op: The http.Transport already supports HTTP/2.
return nil
_, err := configureTransports(t1)
return err
}
func configureTransports(t1 *http.Transport) (*Transport, error) {
@@ -31,6 +31,17 @@ func configureTransports(t1 *http.Transport) (*Transport, error) {
// linked to the http.Transport's.
tr2 := &Transport{}
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
}

2
vendor/modules.txt vendored
View File

@@ -968,7 +968,7 @@ golang.org/x/crypto/xts
# golang.org/x/mod v0.36.0
## explicit; go 1.25.0
golang.org/x/mod/semver
# golang.org/x/net v0.55.0
# golang.org/x/net v0.56.0
## explicit; go 1.25.0
golang.org/x/net/bpf
golang.org/x/net/html