mirror of
https://github.com/podman-container-tools/podman.git
synced 2026-10-26 15:57:38 +00:00
Merge pull request #25650 from cevich/fix_rhel_build
[v4.2.0-rhel] Adjust x/text, x/tools, and x/net versions
This commit is contained in:
commit
adb8ba5e4d
54 changed files with 3148 additions and 8030 deletions
6
go.mod
6
go.mod
|
|
@ -68,7 +68,7 @@ require (
|
|||
golang.org/x/sync v0.11.0
|
||||
golang.org/x/sys v0.30.0
|
||||
golang.org/x/term v0.29.0
|
||||
golang.org/x/text v0.22.0
|
||||
golang.org/x/text v0.15.0
|
||||
google.golang.org/protobuf v1.33.0
|
||||
gopkg.in/inf.v0 v0.9.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
|
|
@ -146,8 +146,8 @@ require (
|
|||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
golang.org/x/net v0.6.0 // indirect
|
||||
golang.org/x/tools v0.6.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f // indirect
|
||||
google.golang.org/grpc v1.47.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
|
|
|
|||
12
go.sum
12
go.sum
|
|
@ -1393,8 +1393,8 @@ golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qx
|
|||
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
|
@ -1553,8 +1553,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
|
@ -1671,8 +1671,8 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.6/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
|
|||
1
vendor/golang.org/x/net/context/go17.go
generated
vendored
1
vendor/golang.org/x/net/context/go17.go
generated
vendored
|
|
@ -3,6 +3,7 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.7
|
||||
// +build go1.7
|
||||
|
||||
package context
|
||||
|
||||
|
|
|
|||
1
vendor/golang.org/x/net/context/go19.go
generated
vendored
1
vendor/golang.org/x/net/context/go19.go
generated
vendored
|
|
@ -3,6 +3,7 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.9
|
||||
// +build go1.9
|
||||
|
||||
package context
|
||||
|
||||
|
|
|
|||
1
vendor/golang.org/x/net/context/pre_go17.go
generated
vendored
1
vendor/golang.org/x/net/context/pre_go17.go
generated
vendored
|
|
@ -3,6 +3,7 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !go1.7
|
||||
// +build !go1.7
|
||||
|
||||
package context
|
||||
|
||||
|
|
|
|||
1
vendor/golang.org/x/net/context/pre_go19.go
generated
vendored
1
vendor/golang.org/x/net/context/pre_go19.go
generated
vendored
|
|
@ -3,6 +3,7 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !go1.9
|
||||
// +build !go1.9
|
||||
|
||||
package context
|
||||
|
||||
|
|
|
|||
21
vendor/golang.org/x/net/html/doc.go
generated
vendored
21
vendor/golang.org/x/net/html/doc.go
generated
vendored
|
|
@ -92,27 +92,6 @@ example, to process each anchor node in depth-first order:
|
|||
The relevant specifications include:
|
||||
https://html.spec.whatwg.org/multipage/syntax.html and
|
||||
https://html.spec.whatwg.org/multipage/syntax.html#tokenization
|
||||
|
||||
# Security Considerations
|
||||
|
||||
Care should be taken when parsing and interpreting HTML, whether full documents
|
||||
or fragments, within the framework of the HTML specification, especially with
|
||||
regard to untrusted inputs.
|
||||
|
||||
This package provides both a tokenizer and a parser, which implement the
|
||||
tokenization, and tokenization and tree construction stages of the WHATWG HTML
|
||||
parsing specification respectively. While the tokenizer parses and normalizes
|
||||
individual HTML tokens, only the parser constructs the DOM tree from the
|
||||
tokenized HTML, as described in the tree construction stage of the
|
||||
specification, dynamically modifying or extending the document's DOM tree.
|
||||
|
||||
If your use case requires semantically well-formed HTML documents, as defined by
|
||||
the WHATWG specification, the parser should be used rather than the tokenizer.
|
||||
|
||||
In security contexts, if trust decisions are being made using the tokenized or
|
||||
parsed content, the input must be re-serialized (for instance by using Render or
|
||||
Token.String) in order for those trust decisions to hold, as the process of
|
||||
tokenization or parsing may alter the content.
|
||||
*/
|
||||
package html // import "golang.org/x/net/html"
|
||||
|
||||
|
|
|
|||
81
vendor/golang.org/x/net/html/escape.go
generated
vendored
81
vendor/golang.org/x/net/html/escape.go
generated
vendored
|
|
@ -193,87 +193,6 @@ func lower(b []byte) []byte {
|
|||
return b
|
||||
}
|
||||
|
||||
// escapeComment is like func escape but escapes its input bytes less often.
|
||||
// Per https://github.com/golang/go/issues/58246 some HTML comments are (1)
|
||||
// meaningful and (2) contain angle brackets that we'd like to avoid escaping
|
||||
// unless we have to.
|
||||
//
|
||||
// "We have to" includes the '&' byte, since that introduces other escapes.
|
||||
//
|
||||
// It also includes those bytes (not including EOF) that would otherwise end
|
||||
// the comment. Per the summary table at the bottom of comment_test.go, this is
|
||||
// the '>' byte that, per above, we'd like to avoid escaping unless we have to.
|
||||
//
|
||||
// Studying the summary table (and T actions in its '>' column) closely, we
|
||||
// only need to escape in states 43, 44, 49, 51 and 52. State 43 is at the
|
||||
// start of the comment data. State 52 is after a '!'. The other three states
|
||||
// are after a '-'.
|
||||
//
|
||||
// Our algorithm is thus to escape every '&' and to escape '>' if and only if:
|
||||
// - The '>' is after a '!' or '-' (in the unescaped data) or
|
||||
// - The '>' is at the start of the comment data (after the opening "<!--").
|
||||
func escapeComment(w writer, s string) error {
|
||||
// When modifying this function, consider manually increasing the
|
||||
// maxSuffixLen constant in func TestComments, from 6 to e.g. 9 or more.
|
||||
// That increase should only be temporary, not committed, as it
|
||||
// exponentially affects the test running time.
|
||||
|
||||
if len(s) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Loop:
|
||||
// - Grow j such that s[i:j] does not need escaping.
|
||||
// - If s[j] does need escaping, output s[i:j] and an escaped s[j],
|
||||
// resetting i and j to point past that s[j] byte.
|
||||
i := 0
|
||||
for j := 0; j < len(s); j++ {
|
||||
escaped := ""
|
||||
switch s[j] {
|
||||
case '&':
|
||||
escaped = "&"
|
||||
|
||||
case '>':
|
||||
if j > 0 {
|
||||
if prev := s[j-1]; (prev != '!') && (prev != '-') {
|
||||
continue
|
||||
}
|
||||
}
|
||||
escaped = ">"
|
||||
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
if i < j {
|
||||
if _, err := w.WriteString(s[i:j]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, err := w.WriteString(escaped); err != nil {
|
||||
return err
|
||||
}
|
||||
i = j + 1
|
||||
}
|
||||
|
||||
if i < len(s) {
|
||||
if _, err := w.WriteString(s[i:]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// escapeCommentString is to EscapeString as escapeComment is to escape.
|
||||
func escapeCommentString(s string) string {
|
||||
if strings.IndexAny(s, "&>") == -1 {
|
||||
return s
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
escapeComment(&buf, s)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
const escapedChars = "&'<>\"\r"
|
||||
|
||||
func escape(w writer, s string) error {
|
||||
|
|
|
|||
30
vendor/golang.org/x/net/html/render.go
generated
vendored
30
vendor/golang.org/x/net/html/render.go
generated
vendored
|
|
@ -85,7 +85,7 @@ func render1(w writer, n *Node) error {
|
|||
if _, err := w.WriteString("<!--"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := escapeComment(w, n.Data); err != nil {
|
||||
if err := escape(w, n.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.WriteString("-->"); err != nil {
|
||||
|
|
@ -194,8 +194,9 @@ func render1(w writer, n *Node) error {
|
|||
}
|
||||
}
|
||||
|
||||
// Render any child nodes
|
||||
if childTextNodesAreLiteral(n) {
|
||||
// Render any child nodes.
|
||||
switch n.Data {
|
||||
case "iframe", "noembed", "noframes", "noscript", "plaintext", "script", "style", "xmp":
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
if c.Type == TextNode {
|
||||
if _, err := w.WriteString(c.Data); err != nil {
|
||||
|
|
@ -212,7 +213,7 @@ func render1(w writer, n *Node) error {
|
|||
// last element in the file, with no closing tag.
|
||||
return plaintextAbort
|
||||
}
|
||||
} else {
|
||||
default:
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
if err := render1(w, c); err != nil {
|
||||
return err
|
||||
|
|
@ -230,27 +231,6 @@ func render1(w writer, n *Node) error {
|
|||
return w.WriteByte('>')
|
||||
}
|
||||
|
||||
func childTextNodesAreLiteral(n *Node) bool {
|
||||
// Per WHATWG HTML 13.3, if the parent of the current node is a style,
|
||||
// script, xmp, iframe, noembed, noframes, or plaintext element, and the
|
||||
// current node is a text node, append the value of the node's data
|
||||
// literally. The specification is not explicit about it, but we only
|
||||
// enforce this if we are in the HTML namespace (i.e. when the namespace is
|
||||
// "").
|
||||
// NOTE: we also always include noscript elements, although the
|
||||
// specification states that they should only be rendered as such if
|
||||
// scripting is enabled for the node (which is not something we track).
|
||||
if n.Namespace != "" {
|
||||
return false
|
||||
}
|
||||
switch n.Data {
|
||||
case "iframe", "noembed", "noframes", "noscript", "plaintext", "script", "style", "xmp":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// writeQuoted writes s to w surrounded by quotes. Normally it will use double
|
||||
// quotes, but if s contains a double quote, it will use single quotes.
|
||||
// It is used for writing the identifiers in a doctype declaration.
|
||||
|
|
|
|||
70
vendor/golang.org/x/net/html/token.go
generated
vendored
70
vendor/golang.org/x/net/html/token.go
generated
vendored
|
|
@ -110,7 +110,7 @@ func (t Token) String() string {
|
|||
case SelfClosingTagToken:
|
||||
return "<" + t.tagString() + "/>"
|
||||
case CommentToken:
|
||||
return "<!--" + escapeCommentString(t.Data) + "-->"
|
||||
return "<!--" + EscapeString(t.Data) + "-->"
|
||||
case DoctypeToken:
|
||||
return "<!DOCTYPE " + EscapeString(t.Data) + ">"
|
||||
}
|
||||
|
|
@ -598,11 +598,6 @@ scriptDataDoubleEscapeEnd:
|
|||
// readComment reads the next comment token starting with "<!--". The opening
|
||||
// "<!--" has already been consumed.
|
||||
func (z *Tokenizer) readComment() {
|
||||
// When modifying this function, consider manually increasing the
|
||||
// maxSuffixLen constant in func TestComments, from 6 to e.g. 9 or more.
|
||||
// That increase should only be temporary, not committed, as it
|
||||
// exponentially affects the test running time.
|
||||
|
||||
z.data.start = z.raw.end
|
||||
defer func() {
|
||||
if z.data.end < z.data.start {
|
||||
|
|
@ -616,7 +611,11 @@ func (z *Tokenizer) readComment() {
|
|||
for {
|
||||
c := z.readByte()
|
||||
if z.err != nil {
|
||||
z.data.end = z.calculateAbruptCommentDataEnd()
|
||||
// Ignore up to two dashes at EOF.
|
||||
if dashCount > 2 {
|
||||
dashCount = 2
|
||||
}
|
||||
z.data.end = z.raw.end - dashCount
|
||||
return
|
||||
}
|
||||
switch c {
|
||||
|
|
@ -632,15 +631,12 @@ func (z *Tokenizer) readComment() {
|
|||
if dashCount >= 2 {
|
||||
c = z.readByte()
|
||||
if z.err != nil {
|
||||
z.data.end = z.calculateAbruptCommentDataEnd()
|
||||
z.data.end = z.raw.end
|
||||
return
|
||||
} else if c == '>' {
|
||||
}
|
||||
if c == '>' {
|
||||
z.data.end = z.raw.end - len("--!>")
|
||||
return
|
||||
} else if c == '-' {
|
||||
dashCount = 1
|
||||
beginning = false
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -649,35 +645,6 @@ func (z *Tokenizer) readComment() {
|
|||
}
|
||||
}
|
||||
|
||||
func (z *Tokenizer) calculateAbruptCommentDataEnd() int {
|
||||
raw := z.Raw()
|
||||
const prefixLen = len("<!--")
|
||||
if len(raw) >= prefixLen {
|
||||
raw = raw[prefixLen:]
|
||||
if hasSuffix(raw, "--!") {
|
||||
return z.raw.end - 3
|
||||
} else if hasSuffix(raw, "--") {
|
||||
return z.raw.end - 2
|
||||
} else if hasSuffix(raw, "-") {
|
||||
return z.raw.end - 1
|
||||
}
|
||||
}
|
||||
return z.raw.end
|
||||
}
|
||||
|
||||
func hasSuffix(b []byte, suffix string) bool {
|
||||
if len(b) < len(suffix) {
|
||||
return false
|
||||
}
|
||||
b = b[len(b)-len(suffix):]
|
||||
for i := range b {
|
||||
if b[i] != suffix[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// readUntilCloseAngle reads until the next ">".
|
||||
func (z *Tokenizer) readUntilCloseAngle() {
|
||||
z.data.start = z.raw.end
|
||||
|
|
@ -910,16 +877,10 @@ func (z *Tokenizer) readTagAttrKey() {
|
|||
return
|
||||
}
|
||||
switch c {
|
||||
case '=':
|
||||
if z.pendingAttr[0].start+1 == z.raw.end {
|
||||
// WHATWG 13.2.5.32, if we see an equals sign before the attribute name
|
||||
// begins, we treat it as a character in the attribute name and continue.
|
||||
continue
|
||||
}
|
||||
fallthrough
|
||||
case ' ', '\n', '\r', '\t', '\f', '/', '>':
|
||||
// WHATWG 13.2.5.33 Attribute name state
|
||||
// We need to reconsume the char in the after attribute name state to support the / character
|
||||
case ' ', '\n', '\r', '\t', '\f', '/':
|
||||
z.pendingAttr[0].end = z.raw.end - 1
|
||||
return
|
||||
case '=', '>':
|
||||
z.raw.end--
|
||||
z.pendingAttr[0].end = z.raw.end
|
||||
return
|
||||
|
|
@ -938,11 +899,6 @@ func (z *Tokenizer) readTagAttrVal() {
|
|||
if z.err != nil {
|
||||
return
|
||||
}
|
||||
if c == '/' {
|
||||
// WHATWG 13.2.5.34 After attribute name state
|
||||
// U+002F SOLIDUS (/) - Switch to the self-closing start tag state.
|
||||
return
|
||||
}
|
||||
if c != '=' {
|
||||
z.raw.end--
|
||||
return
|
||||
|
|
|
|||
13
vendor/golang.org/x/net/http/httpguts/httplex.go
generated
vendored
13
vendor/golang.org/x/net/http/httpguts/httplex.go
generated
vendored
|
|
@ -12,7 +12,7 @@ import (
|
|||
"golang.org/x/net/idna"
|
||||
)
|
||||
|
||||
var isTokenTable = [256]bool{
|
||||
var isTokenTable = [127]bool{
|
||||
'!': true,
|
||||
'#': true,
|
||||
'$': true,
|
||||
|
|
@ -93,7 +93,12 @@ var isTokenTable = [256]bool{
|
|||
}
|
||||
|
||||
func IsTokenRune(r rune) bool {
|
||||
return r < utf8.RuneSelf && isTokenTable[byte(r)]
|
||||
i := int(r)
|
||||
return i < len(isTokenTable) && isTokenTable[i]
|
||||
}
|
||||
|
||||
func isNotToken(r rune) bool {
|
||||
return !IsTokenRune(r)
|
||||
}
|
||||
|
||||
// HeaderValuesContainsToken reports whether any string in values
|
||||
|
|
@ -197,8 +202,8 @@ func ValidHeaderFieldName(v string) bool {
|
|||
if len(v) == 0 {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(v); i++ {
|
||||
if !isTokenTable[v[i]] {
|
||||
for _, r := range v {
|
||||
if !IsTokenRune(r) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
51
vendor/golang.org/x/net/http2/Dockerfile
generated
vendored
Normal file
51
vendor/golang.org/x/net/http2/Dockerfile
generated
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#
|
||||
# This Dockerfile builds a recent curl with HTTP/2 client support, using
|
||||
# a recent nghttp2 build.
|
||||
#
|
||||
# See the Makefile for how to tag it. If Docker and that image is found, the
|
||||
# Go tests use this curl binary for integration tests.
|
||||
#
|
||||
|
||||
FROM ubuntu:trusty
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get upgrade -y && \
|
||||
apt-get install -y git-core build-essential wget
|
||||
|
||||
RUN apt-get install -y --no-install-recommends \
|
||||
autotools-dev libtool pkg-config zlib1g-dev \
|
||||
libcunit1-dev libssl-dev libxml2-dev libevent-dev \
|
||||
automake autoconf
|
||||
|
||||
# The list of packages nghttp2 recommends for h2load:
|
||||
RUN apt-get install -y --no-install-recommends make binutils \
|
||||
autoconf automake autotools-dev \
|
||||
libtool pkg-config zlib1g-dev libcunit1-dev libssl-dev libxml2-dev \
|
||||
libev-dev libevent-dev libjansson-dev libjemalloc-dev \
|
||||
cython python3.4-dev python-setuptools
|
||||
|
||||
# Note: setting NGHTTP2_VER before the git clone, so an old git clone isn't cached:
|
||||
ENV NGHTTP2_VER 895da9a
|
||||
RUN cd /root && git clone https://github.com/tatsuhiro-t/nghttp2.git
|
||||
|
||||
WORKDIR /root/nghttp2
|
||||
RUN git reset --hard $NGHTTP2_VER
|
||||
RUN autoreconf -i
|
||||
RUN automake
|
||||
RUN autoconf
|
||||
RUN ./configure
|
||||
RUN make
|
||||
RUN make install
|
||||
|
||||
WORKDIR /root
|
||||
RUN wget https://curl.se/download/curl-7.45.0.tar.gz
|
||||
RUN tar -zxvf curl-7.45.0.tar.gz
|
||||
WORKDIR /root/curl-7.45.0
|
||||
RUN ./configure --with-ssl --with-nghttp2=/usr/local
|
||||
RUN make
|
||||
RUN make install
|
||||
RUN ldconfig
|
||||
|
||||
CMD ["-h"]
|
||||
ENTRYPOINT ["/usr/local/bin/curl"]
|
||||
|
||||
3
vendor/golang.org/x/net/http2/Makefile
generated
vendored
Normal file
3
vendor/golang.org/x/net/http2/Makefile
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
curlimage:
|
||||
docker build -t gohttp2/curl .
|
||||
|
||||
59
vendor/golang.org/x/net/http2/databuffer.go
generated
vendored
59
vendor/golang.org/x/net/http2/databuffer.go
generated
vendored
|
|
@ -20,44 +20,41 @@ import (
|
|||
// TODO: Benchmark to determine if the pools are necessary. The GC may have
|
||||
// improved enough that we can instead allocate chunks like this:
|
||||
// make([]byte, max(16<<10, expectedBytesRemaining))
|
||||
var dataChunkPools = [...]sync.Pool{
|
||||
{New: func() interface{} { return new([1 << 10]byte) }},
|
||||
{New: func() interface{} { return new([2 << 10]byte) }},
|
||||
{New: func() interface{} { return new([4 << 10]byte) }},
|
||||
{New: func() interface{} { return new([8 << 10]byte) }},
|
||||
{New: func() interface{} { return new([16 << 10]byte) }},
|
||||
}
|
||||
var (
|
||||
dataChunkSizeClasses = []int{
|
||||
1 << 10,
|
||||
2 << 10,
|
||||
4 << 10,
|
||||
8 << 10,
|
||||
16 << 10,
|
||||
}
|
||||
dataChunkPools = [...]sync.Pool{
|
||||
{New: func() interface{} { return make([]byte, 1<<10) }},
|
||||
{New: func() interface{} { return make([]byte, 2<<10) }},
|
||||
{New: func() interface{} { return make([]byte, 4<<10) }},
|
||||
{New: func() interface{} { return make([]byte, 8<<10) }},
|
||||
{New: func() interface{} { return make([]byte, 16<<10) }},
|
||||
}
|
||||
)
|
||||
|
||||
func getDataBufferChunk(size int64) []byte {
|
||||
switch {
|
||||
case size <= 1<<10:
|
||||
return dataChunkPools[0].Get().(*[1 << 10]byte)[:]
|
||||
case size <= 2<<10:
|
||||
return dataChunkPools[1].Get().(*[2 << 10]byte)[:]
|
||||
case size <= 4<<10:
|
||||
return dataChunkPools[2].Get().(*[4 << 10]byte)[:]
|
||||
case size <= 8<<10:
|
||||
return dataChunkPools[3].Get().(*[8 << 10]byte)[:]
|
||||
default:
|
||||
return dataChunkPools[4].Get().(*[16 << 10]byte)[:]
|
||||
i := 0
|
||||
for ; i < len(dataChunkSizeClasses)-1; i++ {
|
||||
if size <= int64(dataChunkSizeClasses[i]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return dataChunkPools[i].Get().([]byte)
|
||||
}
|
||||
|
||||
func putDataBufferChunk(p []byte) {
|
||||
switch len(p) {
|
||||
case 1 << 10:
|
||||
dataChunkPools[0].Put((*[1 << 10]byte)(p))
|
||||
case 2 << 10:
|
||||
dataChunkPools[1].Put((*[2 << 10]byte)(p))
|
||||
case 4 << 10:
|
||||
dataChunkPools[2].Put((*[4 << 10]byte)(p))
|
||||
case 8 << 10:
|
||||
dataChunkPools[3].Put((*[8 << 10]byte)(p))
|
||||
case 16 << 10:
|
||||
dataChunkPools[4].Put((*[16 << 10]byte)(p))
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected buffer len=%v", len(p)))
|
||||
for i, n := range dataChunkSizeClasses {
|
||||
if len(p) == n {
|
||||
dataChunkPools[i].Put(p)
|
||||
return
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("unexpected buffer len=%v", len(p)))
|
||||
}
|
||||
|
||||
// dataBuffer is an io.ReadWriter backed by a list of data chunks.
|
||||
|
|
|
|||
62
vendor/golang.org/x/net/http2/frame.go
generated
vendored
62
vendor/golang.org/x/net/http2/frame.go
generated
vendored
|
|
@ -490,9 +490,6 @@ func terminalReadFrameError(err error) bool {
|
|||
// returned error is ErrFrameTooLarge. Other errors may be of type
|
||||
// ConnectionError, StreamError, or anything else from the underlying
|
||||
// reader.
|
||||
//
|
||||
// If ReadFrame returns an error and a non-nil Frame, the Frame's StreamID
|
||||
// indicates the stream responsible for the error.
|
||||
func (fr *Framer) ReadFrame() (Frame, error) {
|
||||
fr.errDetail = nil
|
||||
if fr.lastFrame != nil {
|
||||
|
|
@ -665,15 +662,6 @@ func (f *Framer) WriteData(streamID uint32, endStream bool, data []byte) error {
|
|||
// It is the caller's responsibility not to violate the maximum frame size
|
||||
// and to not call other Write methods concurrently.
|
||||
func (f *Framer) WriteDataPadded(streamID uint32, endStream bool, data, pad []byte) error {
|
||||
if err := f.startWriteDataPadded(streamID, endStream, data, pad); err != nil {
|
||||
return err
|
||||
}
|
||||
return f.endWrite()
|
||||
}
|
||||
|
||||
// startWriteDataPadded is WriteDataPadded, but only writes the frame to the Framer's internal buffer.
|
||||
// The caller should call endWrite to flush the frame to the underlying writer.
|
||||
func (f *Framer) startWriteDataPadded(streamID uint32, endStream bool, data, pad []byte) error {
|
||||
if !validStreamID(streamID) && !f.AllowIllegalWrites {
|
||||
return errStreamID
|
||||
}
|
||||
|
|
@ -703,7 +691,7 @@ func (f *Framer) startWriteDataPadded(streamID uint32, endStream bool, data, pad
|
|||
}
|
||||
f.wbuf = append(f.wbuf, data...)
|
||||
f.wbuf = append(f.wbuf, pad...)
|
||||
return nil
|
||||
return f.endWrite()
|
||||
}
|
||||
|
||||
// A SettingsFrame conveys configuration parameters that affect how
|
||||
|
|
@ -1513,18 +1501,19 @@ func (mh *MetaHeadersFrame) checkPseudos() error {
|
|||
}
|
||||
|
||||
func (fr *Framer) maxHeaderStringLen() int {
|
||||
v := int(fr.maxHeaderListSize())
|
||||
if v < 0 {
|
||||
// If maxHeaderListSize overflows an int, use no limit (0).
|
||||
return 0
|
||||
v := fr.maxHeaderListSize()
|
||||
if uint32(int(v)) == v {
|
||||
return int(v)
|
||||
}
|
||||
return v
|
||||
// They had a crazy big number for MaxHeaderBytes anyway,
|
||||
// so give them unlimited header lengths:
|
||||
return 0
|
||||
}
|
||||
|
||||
// readMetaFrame returns 0 or more CONTINUATION frames from fr and
|
||||
// merge them into the provided hf and returns a MetaHeadersFrame
|
||||
// with the decoded hpack values.
|
||||
func (fr *Framer) readMetaFrame(hf *HeadersFrame) (Frame, error) {
|
||||
func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) {
|
||||
if fr.AllowIllegalReads {
|
||||
return nil, errors.New("illegal use of AllowIllegalReads with ReadMetaHeaders")
|
||||
}
|
||||
|
|
@ -1567,7 +1556,6 @@ func (fr *Framer) readMetaFrame(hf *HeadersFrame) (Frame, error) {
|
|||
if size > remainSize {
|
||||
hdec.SetEmitEnabled(false)
|
||||
mh.Truncated = true
|
||||
remainSize = 0
|
||||
return
|
||||
}
|
||||
remainSize -= size
|
||||
|
|
@ -1580,38 +1568,8 @@ func (fr *Framer) readMetaFrame(hf *HeadersFrame) (Frame, error) {
|
|||
var hc headersOrContinuation = hf
|
||||
for {
|
||||
frag := hc.HeaderBlockFragment()
|
||||
|
||||
// Avoid parsing large amounts of headers that we will then discard.
|
||||
// If the sender exceeds the max header list size by too much,
|
||||
// skip parsing the fragment and close the connection.
|
||||
//
|
||||
// "Too much" is either any CONTINUATION frame after we've already
|
||||
// exceeded the max header list size (in which case remainSize is 0),
|
||||
// or a frame whose encoded size is more than twice the remaining
|
||||
// header list bytes we're willing to accept.
|
||||
if int64(len(frag)) > int64(2*remainSize) {
|
||||
if VerboseLogs {
|
||||
log.Printf("http2: header list too large")
|
||||
}
|
||||
// It would be nice to send a RST_STREAM before sending the GOAWAY,
|
||||
// but the structure of the server's frame writer makes this difficult.
|
||||
return mh, ConnectionError(ErrCodeProtocol)
|
||||
}
|
||||
|
||||
// Also close the connection after any CONTINUATION frame following an
|
||||
// invalid header, since we stop tracking the size of the headers after
|
||||
// an invalid one.
|
||||
if invalid != nil {
|
||||
if VerboseLogs {
|
||||
log.Printf("http2: invalid header: %v", invalid)
|
||||
}
|
||||
// It would be nice to send a RST_STREAM before sending the GOAWAY,
|
||||
// but the structure of the server's frame writer makes this difficult.
|
||||
return mh, ConnectionError(ErrCodeProtocol)
|
||||
}
|
||||
|
||||
if _, err := hdec.Write(frag); err != nil {
|
||||
return mh, ConnectionError(ErrCodeCompression)
|
||||
return nil, ConnectionError(ErrCodeCompression)
|
||||
}
|
||||
|
||||
if hc.HeadersEnded() {
|
||||
|
|
@ -1628,7 +1586,7 @@ func (fr *Framer) readMetaFrame(hf *HeadersFrame) (Frame, error) {
|
|||
mh.HeadersFrame.invalidate()
|
||||
|
||||
if err := hdec.Close(); err != nil {
|
||||
return mh, ConnectionError(ErrCodeCompression)
|
||||
return nil, ConnectionError(ErrCodeCompression)
|
||||
}
|
||||
if invalid != nil {
|
||||
fr.errDetail = invalid
|
||||
|
|
|
|||
30
vendor/golang.org/x/net/http2/go111.go
generated
vendored
Normal file
30
vendor/golang.org/x/net/http2/go111.go
generated
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2018 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.
|
||||
|
||||
//go:build go1.11
|
||||
// +build go1.11
|
||||
|
||||
package http2
|
||||
|
||||
import (
|
||||
"net/http/httptrace"
|
||||
"net/textproto"
|
||||
)
|
||||
|
||||
func traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool {
|
||||
return trace != nil && trace.WroteHeaderField != nil
|
||||
}
|
||||
|
||||
func traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) {
|
||||
if trace != nil && trace.WroteHeaderField != nil {
|
||||
trace.WroteHeaderField(k, []string{v})
|
||||
}
|
||||
}
|
||||
|
||||
func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error {
|
||||
if trace != nil {
|
||||
return trace.Got1xxResponse
|
||||
}
|
||||
return nil
|
||||
}
|
||||
27
vendor/golang.org/x/net/http2/go115.go
generated
vendored
Normal file
27
vendor/golang.org/x/net/http2/go115.go
generated
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2021 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.
|
||||
|
||||
//go:build go1.15
|
||||
// +build go1.15
|
||||
|
||||
package http2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
)
|
||||
|
||||
// dialTLSWithContext uses tls.Dialer, added in Go 1.15, to open a TLS
|
||||
// connection.
|
||||
func (t *Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) {
|
||||
dialer := &tls.Dialer{
|
||||
Config: cfg,
|
||||
}
|
||||
cn, err := dialer.DialContext(ctx, network, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsCn := cn.(*tls.Conn) // DialContext comment promises this will always succeed
|
||||
return tlsCn, nil
|
||||
}
|
||||
17
vendor/golang.org/x/net/http2/go118.go
generated
vendored
Normal file
17
vendor/golang.org/x/net/http2/go118.go
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2021 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.
|
||||
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
package http2
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net"
|
||||
)
|
||||
|
||||
func tlsUnderlyingConn(tc *tls.Conn) net.Conn {
|
||||
return tc.NetConn()
|
||||
}
|
||||
79
vendor/golang.org/x/net/http2/hpack/hpack.go
generated
vendored
79
vendor/golang.org/x/net/http2/hpack/hpack.go
generated
vendored
|
|
@ -359,7 +359,6 @@ func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error {
|
|||
|
||||
var hf HeaderField
|
||||
wantStr := d.emitEnabled || it.indexed()
|
||||
var undecodedName undecodedString
|
||||
if nameIdx > 0 {
|
||||
ihf, ok := d.at(nameIdx)
|
||||
if !ok {
|
||||
|
|
@ -367,27 +366,15 @@ func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error {
|
|||
}
|
||||
hf.Name = ihf.Name
|
||||
} else {
|
||||
undecodedName, buf, err = d.readString(buf)
|
||||
hf.Name, buf, err = d.readString(buf, wantStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
undecodedValue, buf, err := d.readString(buf)
|
||||
hf.Value, buf, err = d.readString(buf, wantStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if wantStr {
|
||||
if nameIdx <= 0 {
|
||||
hf.Name, err = d.decodeString(undecodedName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
hf.Value, err = d.decodeString(undecodedValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
d.buf = buf
|
||||
if it.indexed() {
|
||||
d.dynTab.add(hf)
|
||||
|
|
@ -472,52 +459,46 @@ func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) {
|
|||
return 0, origP, errNeedMore
|
||||
}
|
||||
|
||||
// readString reads an hpack string from p.
|
||||
// readString decodes an hpack string from p.
|
||||
//
|
||||
// It returns a reference to the encoded string data to permit deferring decode costs
|
||||
// until after the caller verifies all data is present.
|
||||
func (d *Decoder) readString(p []byte) (u undecodedString, remain []byte, err error) {
|
||||
// wantStr is whether s will be used. If false, decompression and
|
||||
// []byte->string garbage are skipped if s will be ignored
|
||||
// anyway. This does mean that huffman decoding errors for non-indexed
|
||||
// strings past the MAX_HEADER_LIST_SIZE are ignored, but the server
|
||||
// is returning an error anyway, and because they're not indexed, the error
|
||||
// won't affect the decoding state.
|
||||
func (d *Decoder) readString(p []byte, wantStr bool) (s string, remain []byte, err error) {
|
||||
if len(p) == 0 {
|
||||
return u, p, errNeedMore
|
||||
return "", p, errNeedMore
|
||||
}
|
||||
isHuff := p[0]&128 != 0
|
||||
strLen, p, err := readVarInt(7, p)
|
||||
if err != nil {
|
||||
return u, p, err
|
||||
return "", p, err
|
||||
}
|
||||
if d.maxStrLen != 0 && strLen > uint64(d.maxStrLen) {
|
||||
// Returning an error here means Huffman decoding errors
|
||||
// for non-indexed strings past the maximum string length
|
||||
// are ignored, but the server is returning an error anyway
|
||||
// and because the string is not indexed the error will not
|
||||
// affect the decoding state.
|
||||
return u, nil, ErrStringLength
|
||||
return "", nil, ErrStringLength
|
||||
}
|
||||
if uint64(len(p)) < strLen {
|
||||
return u, p, errNeedMore
|
||||
return "", p, errNeedMore
|
||||
}
|
||||
u.isHuff = isHuff
|
||||
u.b = p[:strLen]
|
||||
return u, p[strLen:], nil
|
||||
}
|
||||
|
||||
type undecodedString struct {
|
||||
isHuff bool
|
||||
b []byte
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeString(u undecodedString) (string, error) {
|
||||
if !u.isHuff {
|
||||
return string(u.b), nil
|
||||
if !isHuff {
|
||||
if wantStr {
|
||||
s = string(p[:strLen])
|
||||
}
|
||||
return s, p[strLen:], nil
|
||||
}
|
||||
buf := bufPool.Get().(*bytes.Buffer)
|
||||
buf.Reset() // don't trust others
|
||||
var s string
|
||||
err := huffmanDecode(buf, d.maxStrLen, u.b)
|
||||
if err == nil {
|
||||
|
||||
if wantStr {
|
||||
buf := bufPool.Get().(*bytes.Buffer)
|
||||
buf.Reset() // don't trust others
|
||||
defer bufPool.Put(buf)
|
||||
if err := huffmanDecode(buf, d.maxStrLen, p[:strLen]); err != nil {
|
||||
buf.Reset()
|
||||
return "", nil, err
|
||||
}
|
||||
s = buf.String()
|
||||
buf.Reset() // be nice to GC
|
||||
}
|
||||
buf.Reset() // be nice to GC
|
||||
bufPool.Put(buf)
|
||||
return s, err
|
||||
return s, p[strLen:], nil
|
||||
}
|
||||
|
|
|
|||
21
vendor/golang.org/x/net/http2/not_go111.go
generated
vendored
Normal file
21
vendor/golang.org/x/net/http2/not_go111.go
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2018 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.
|
||||
|
||||
//go:build !go1.11
|
||||
// +build !go1.11
|
||||
|
||||
package http2
|
||||
|
||||
import (
|
||||
"net/http/httptrace"
|
||||
"net/textproto"
|
||||
)
|
||||
|
||||
func traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool { return false }
|
||||
|
||||
func traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) {}
|
||||
|
||||
func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error {
|
||||
return nil
|
||||
}
|
||||
31
vendor/golang.org/x/net/http2/not_go115.go
generated
vendored
Normal file
31
vendor/golang.org/x/net/http2/not_go115.go
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2021 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.
|
||||
|
||||
//go:build !go1.15
|
||||
// +build !go1.15
|
||||
|
||||
package http2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
)
|
||||
|
||||
// dialTLSWithContext opens a TLS connection.
|
||||
func (t *Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) {
|
||||
cn, err := tls.Dial(network, addr, cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := cn.Handshake(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cfg.InsecureSkipVerify {
|
||||
return cn, nil
|
||||
}
|
||||
if err := cn.VerifyHostname(cfg.ServerName); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cn, nil
|
||||
}
|
||||
17
vendor/golang.org/x/net/http2/not_go118.go
generated
vendored
Normal file
17
vendor/golang.org/x/net/http2/not_go118.go
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2021 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.
|
||||
|
||||
//go:build !go1.18
|
||||
// +build !go1.18
|
||||
|
||||
package http2
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net"
|
||||
)
|
||||
|
||||
func tlsUnderlyingConn(tc *tls.Conn) net.Conn {
|
||||
return nil
|
||||
}
|
||||
15
vendor/golang.org/x/net/http2/pipe.go
generated
vendored
15
vendor/golang.org/x/net/http2/pipe.go
generated
vendored
|
|
@ -77,10 +77,7 @@ func (p *pipe) Read(d []byte) (n int, err error) {
|
|||
}
|
||||
}
|
||||
|
||||
var (
|
||||
errClosedPipeWrite = errors.New("write on closed buffer")
|
||||
errUninitializedPipeWrite = errors.New("write on uninitialized buffer")
|
||||
)
|
||||
var errClosedPipeWrite = errors.New("write on closed buffer")
|
||||
|
||||
// Write copies bytes from p into the buffer and wakes a reader.
|
||||
// It is an error to write more data than the buffer can hold.
|
||||
|
|
@ -91,14 +88,12 @@ func (p *pipe) Write(d []byte) (n int, err error) {
|
|||
p.c.L = &p.mu
|
||||
}
|
||||
defer p.c.Signal()
|
||||
if p.err != nil || p.breakErr != nil {
|
||||
if p.err != nil {
|
||||
return 0, errClosedPipeWrite
|
||||
}
|
||||
// pipe.setBuffer is never invoked, leaving the buffer uninitialized.
|
||||
// We shouldn't try to write to an uninitialized pipe,
|
||||
// but returning an error is better than panicking.
|
||||
if p.b == nil {
|
||||
return 0, errUninitializedPipeWrite
|
||||
if p.breakErr != nil {
|
||||
p.unread += len(d)
|
||||
return len(d), nil // discard when there is no reader
|
||||
}
|
||||
return p.b.Write(d)
|
||||
}
|
||||
|
|
|
|||
168
vendor/golang.org/x/net/http2/server.go
generated
vendored
168
vendor/golang.org/x/net/http2/server.go
generated
vendored
|
|
@ -124,7 +124,6 @@ type Server struct {
|
|||
// IdleTimeout specifies how long until idle clients should be
|
||||
// closed with a GOAWAY frame. PING frames are not considered
|
||||
// activity for the purposes of IdleTimeout.
|
||||
// If zero or negative, there is no timeout.
|
||||
IdleTimeout time.Duration
|
||||
|
||||
// MaxUploadBufferPerConnection is the size of the initial flow
|
||||
|
|
@ -435,14 +434,14 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
|
|||
// passes the connection off to us with the deadline already set.
|
||||
// Write deadlines are set per stream in serverConn.newStream.
|
||||
// Disarm the net.Conn write deadline here.
|
||||
if sc.hs.WriteTimeout > 0 {
|
||||
if sc.hs.WriteTimeout != 0 {
|
||||
sc.conn.SetWriteDeadline(time.Time{})
|
||||
}
|
||||
|
||||
if s.NewWriteScheduler != nil {
|
||||
sc.writeSched = s.NewWriteScheduler()
|
||||
} else {
|
||||
sc.writeSched = newRoundRobinWriteScheduler()
|
||||
sc.writeSched = NewPriorityWriteScheduler(nil)
|
||||
}
|
||||
|
||||
// These start at the RFC-specified defaults. If there is a higher
|
||||
|
|
@ -582,11 +581,9 @@ type serverConn struct {
|
|||
advMaxStreams uint32 // our SETTINGS_MAX_CONCURRENT_STREAMS advertised the client
|
||||
curClientStreams uint32 // number of open streams initiated by the client
|
||||
curPushedStreams uint32 // number of open streams initiated by server push
|
||||
curHandlers uint32 // number of running handler goroutines
|
||||
maxClientStreamID uint32 // max ever seen from client (odd), or 0 if there have been no client requests
|
||||
maxPushPromiseID uint32 // ID of the last push promise (even), or 0 if there have been no pushes
|
||||
streams map[uint32]*stream
|
||||
unstartedHandlers []unstartedHandler
|
||||
initialStreamSendWindowSize int32
|
||||
maxFrameSize int32
|
||||
peerMaxHeaderListSize uint32 // zero means unknown (default)
|
||||
|
|
@ -732,7 +729,11 @@ func isClosedConnError(err error) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
if errors.Is(err, net.ErrClosed) {
|
||||
// TODO: remove this string search and be more like the Windows
|
||||
// case below. That might involve modifying the standard library
|
||||
// to return better error types.
|
||||
str := err.Error()
|
||||
if strings.Contains(str, "use of closed network connection") {
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -842,13 +843,8 @@ type frameWriteResult struct {
|
|||
// and then reports when it's done.
|
||||
// At most one goroutine can be running writeFrameAsync at a time per
|
||||
// serverConn.
|
||||
func (sc *serverConn) writeFrameAsync(wr FrameWriteRequest, wd *writeData) {
|
||||
var err error
|
||||
if wd == nil {
|
||||
err = wr.write.writeFrame(sc)
|
||||
} else {
|
||||
err = sc.framer.endWrite()
|
||||
}
|
||||
func (sc *serverConn) writeFrameAsync(wr FrameWriteRequest) {
|
||||
err := wr.write.writeFrame(sc)
|
||||
sc.wroteFrameCh <- frameWriteResult{wr: wr, err: err}
|
||||
}
|
||||
|
||||
|
|
@ -921,7 +917,7 @@ func (sc *serverConn) serve() {
|
|||
sc.setConnState(http.StateActive)
|
||||
sc.setConnState(http.StateIdle)
|
||||
|
||||
if sc.srv.IdleTimeout > 0 {
|
||||
if sc.srv.IdleTimeout != 0 {
|
||||
sc.idleTimer = time.AfterFunc(sc.srv.IdleTimeout, sc.onIdleTimer)
|
||||
defer sc.idleTimer.Stop()
|
||||
}
|
||||
|
|
@ -980,8 +976,6 @@ func (sc *serverConn) serve() {
|
|||
return
|
||||
case gracefulShutdownMsg:
|
||||
sc.startGracefulShutdownInternal()
|
||||
case handlerDoneMsg:
|
||||
sc.handlerDone()
|
||||
default:
|
||||
panic("unknown timer")
|
||||
}
|
||||
|
|
@ -1013,6 +1007,14 @@ func (sc *serverConn) serve() {
|
|||
}
|
||||
}
|
||||
|
||||
func (sc *serverConn) awaitGracefulShutdown(sharedCh <-chan struct{}, privateCh chan struct{}) {
|
||||
select {
|
||||
case <-sc.doneServing:
|
||||
case <-sharedCh:
|
||||
close(privateCh)
|
||||
}
|
||||
}
|
||||
|
||||
type serverMessage int
|
||||
|
||||
// Message values sent to serveMsgCh.
|
||||
|
|
@ -1021,7 +1023,6 @@ var (
|
|||
idleTimerMsg = new(serverMessage)
|
||||
shutdownTimerMsg = new(serverMessage)
|
||||
gracefulShutdownMsg = new(serverMessage)
|
||||
handlerDoneMsg = new(serverMessage)
|
||||
)
|
||||
|
||||
func (sc *serverConn) onSettingsTimer() { sc.sendServeMsg(settingsTimerMsg) }
|
||||
|
|
@ -1250,16 +1251,9 @@ func (sc *serverConn) startFrameWrite(wr FrameWriteRequest) {
|
|||
sc.writingFrameAsync = false
|
||||
err := wr.write.writeFrame(sc)
|
||||
sc.wroteFrame(frameWriteResult{wr: wr, err: err})
|
||||
} else if wd, ok := wr.write.(*writeData); ok {
|
||||
// Encode the frame in the serve goroutine, to ensure we don't have
|
||||
// any lingering asynchronous references to data passed to Write.
|
||||
// See https://go.dev/issue/58446.
|
||||
sc.framer.startWriteDataPadded(wd.streamID, wd.endStream, wd.p, nil)
|
||||
sc.writingFrameAsync = true
|
||||
go sc.writeFrameAsync(wr, wd)
|
||||
} else {
|
||||
sc.writingFrameAsync = true
|
||||
go sc.writeFrameAsync(wr, nil)
|
||||
go sc.writeFrameAsync(wr)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1478,11 +1472,6 @@ func (sc *serverConn) processFrameFromReader(res readFrameResult) bool {
|
|||
sc.goAway(ErrCodeFlowControl)
|
||||
return true
|
||||
case ConnectionError:
|
||||
if res.f != nil {
|
||||
if id := res.f.Header().StreamID; id > sc.maxClientStreamID {
|
||||
sc.maxClientStreamID = id
|
||||
}
|
||||
}
|
||||
sc.logf("http2: server connection error from %v: %v", sc.conn.RemoteAddr(), ev)
|
||||
sc.goAway(ErrCode(ev))
|
||||
return true // goAway will handle shutdown
|
||||
|
|
@ -1639,7 +1628,7 @@ func (sc *serverConn) closeStream(st *stream, err error) {
|
|||
delete(sc.streams, st.id)
|
||||
if len(sc.streams) == 0 {
|
||||
sc.setConnState(http.StateIdle)
|
||||
if sc.srv.IdleTimeout > 0 {
|
||||
if sc.srv.IdleTimeout != 0 {
|
||||
sc.idleTimer.Reset(sc.srv.IdleTimeout)
|
||||
}
|
||||
if h1ServerKeepAlivesDisabled(sc.hs) {
|
||||
|
|
@ -1821,18 +1810,15 @@ func (sc *serverConn) processData(f *DataFrame) error {
|
|||
}
|
||||
|
||||
if len(data) > 0 {
|
||||
st.bodyBytes += int64(len(data))
|
||||
wrote, err := st.body.Write(data)
|
||||
if err != nil {
|
||||
// The handler has closed the request body.
|
||||
// Return the connection-level flow control for the discarded data,
|
||||
// but not the stream-level flow control.
|
||||
sc.sendWindowUpdate(nil, int(f.Length)-wrote)
|
||||
return nil
|
||||
return sc.countError("body_write_err", streamError(id, ErrCodeStreamClosed))
|
||||
}
|
||||
if wrote != len(data) {
|
||||
panic("internal error: bad Writer")
|
||||
}
|
||||
st.bodyBytes += int64(len(data))
|
||||
}
|
||||
|
||||
// Return any padded flow control now, since we won't
|
||||
|
|
@ -1899,11 +1885,9 @@ func (st *stream) copyTrailersToHandlerRequest() {
|
|||
// onReadTimeout is run on its own goroutine (from time.AfterFunc)
|
||||
// when the stream's ReadTimeout has fired.
|
||||
func (st *stream) onReadTimeout() {
|
||||
if st.body != nil {
|
||||
// Wrap the ErrDeadlineExceeded to avoid callers depending on us
|
||||
// returning the bare error.
|
||||
st.body.CloseWithError(fmt.Errorf("%w", os.ErrDeadlineExceeded))
|
||||
}
|
||||
// Wrap the ErrDeadlineExceeded to avoid callers depending on us
|
||||
// returning the bare error.
|
||||
st.body.CloseWithError(fmt.Errorf("%w", os.ErrDeadlineExceeded))
|
||||
}
|
||||
|
||||
// onWriteTimeout is run on its own goroutine (from time.AfterFunc)
|
||||
|
|
@ -2019,12 +2003,15 @@ func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {
|
|||
// similar to how the http1 server works. Here it's
|
||||
// technically more like the http1 Server's ReadHeaderTimeout
|
||||
// (in Go 1.8), though. That's a more sane option anyway.
|
||||
if sc.hs.ReadTimeout > 0 {
|
||||
if sc.hs.ReadTimeout != 0 {
|
||||
sc.conn.SetReadDeadline(time.Time{})
|
||||
st.readDeadline = time.AfterFunc(sc.hs.ReadTimeout, st.onReadTimeout)
|
||||
if st.body != nil {
|
||||
st.readDeadline = time.AfterFunc(sc.hs.ReadTimeout, st.onReadTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
return sc.scheduleHandler(id, rw, req, handler)
|
||||
go sc.runHandler(rw, req, handler)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sc *serverConn) upgradeRequest(req *http.Request) {
|
||||
|
|
@ -2040,14 +2027,10 @@ func (sc *serverConn) upgradeRequest(req *http.Request) {
|
|||
|
||||
// Disable any read deadline set by the net/http package
|
||||
// prior to the upgrade.
|
||||
if sc.hs.ReadTimeout > 0 {
|
||||
if sc.hs.ReadTimeout != 0 {
|
||||
sc.conn.SetReadDeadline(time.Time{})
|
||||
}
|
||||
|
||||
// This is the first request on the connection,
|
||||
// so start the handler directly rather than going
|
||||
// through scheduleHandler.
|
||||
sc.curHandlers++
|
||||
go sc.runHandler(rw, req, sc.handler.ServeHTTP)
|
||||
}
|
||||
|
||||
|
|
@ -2118,7 +2101,7 @@ func (sc *serverConn) newStream(id, pusherID uint32, state streamState) *stream
|
|||
st.flow.conn = &sc.flow // link to conn-level counter
|
||||
st.flow.add(sc.initialStreamSendWindowSize)
|
||||
st.inflow.init(sc.srv.initialStreamRecvWindowSize())
|
||||
if sc.hs.WriteTimeout > 0 {
|
||||
if sc.hs.WriteTimeout != 0 {
|
||||
st.writeDeadline = time.AfterFunc(sc.hs.WriteTimeout, st.onWriteTimeout)
|
||||
}
|
||||
|
||||
|
|
@ -2288,62 +2271,8 @@ func (sc *serverConn) newResponseWriter(st *stream, req *http.Request) *response
|
|||
return &responseWriter{rws: rws}
|
||||
}
|
||||
|
||||
type unstartedHandler struct {
|
||||
streamID uint32
|
||||
rw *responseWriter
|
||||
req *http.Request
|
||||
handler func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
|
||||
// scheduleHandler starts a handler goroutine,
|
||||
// or schedules one to start as soon as an existing handler finishes.
|
||||
func (sc *serverConn) scheduleHandler(streamID uint32, rw *responseWriter, req *http.Request, handler func(http.ResponseWriter, *http.Request)) error {
|
||||
sc.serveG.check()
|
||||
maxHandlers := sc.advMaxStreams
|
||||
if sc.curHandlers < maxHandlers {
|
||||
sc.curHandlers++
|
||||
go sc.runHandler(rw, req, handler)
|
||||
return nil
|
||||
}
|
||||
if len(sc.unstartedHandlers) > int(4*sc.advMaxStreams) {
|
||||
return sc.countError("too_many_early_resets", ConnectionError(ErrCodeEnhanceYourCalm))
|
||||
}
|
||||
sc.unstartedHandlers = append(sc.unstartedHandlers, unstartedHandler{
|
||||
streamID: streamID,
|
||||
rw: rw,
|
||||
req: req,
|
||||
handler: handler,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sc *serverConn) handlerDone() {
|
||||
sc.serveG.check()
|
||||
sc.curHandlers--
|
||||
i := 0
|
||||
maxHandlers := sc.advMaxStreams
|
||||
for ; i < len(sc.unstartedHandlers); i++ {
|
||||
u := sc.unstartedHandlers[i]
|
||||
if sc.streams[u.streamID] == nil {
|
||||
// This stream was reset before its goroutine had a chance to start.
|
||||
continue
|
||||
}
|
||||
if sc.curHandlers >= maxHandlers {
|
||||
break
|
||||
}
|
||||
sc.curHandlers++
|
||||
go sc.runHandler(u.rw, u.req, u.handler)
|
||||
sc.unstartedHandlers[i] = unstartedHandler{} // don't retain references
|
||||
}
|
||||
sc.unstartedHandlers = sc.unstartedHandlers[i:]
|
||||
if len(sc.unstartedHandlers) == 0 {
|
||||
sc.unstartedHandlers = nil
|
||||
}
|
||||
}
|
||||
|
||||
// Run on its own goroutine.
|
||||
func (sc *serverConn) runHandler(rw *responseWriter, req *http.Request, handler func(http.ResponseWriter, *http.Request)) {
|
||||
defer sc.sendServeMsg(handlerDoneMsg)
|
||||
didPanic := true
|
||||
defer func() {
|
||||
rw.rws.stream.cancelCtx()
|
||||
|
|
@ -2485,7 +2414,7 @@ type requestBody struct {
|
|||
conn *serverConn
|
||||
closeOnce sync.Once // for use by Close only
|
||||
sawEOF bool // for use by Read only
|
||||
pipe *pipe // non-nil if we have an HTTP entity message body
|
||||
pipe *pipe // non-nil if we have a HTTP entity message body
|
||||
needsContinue bool // need to send a 100-continue
|
||||
}
|
||||
|
||||
|
|
@ -2551,6 +2480,7 @@ type responseWriterState struct {
|
|||
wroteHeader bool // WriteHeader called (explicitly or implicitly). Not necessarily sent to user yet.
|
||||
sentHeader bool // have we sent the header frame?
|
||||
handlerDone bool // handler has finished
|
||||
dirty bool // a Write failed; don't reuse this responseWriterState
|
||||
|
||||
sentContentLen int64 // non-zero if handler set a Content-Length header
|
||||
wroteBytes int64
|
||||
|
|
@ -2624,8 +2554,7 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
|
|||
clen = ""
|
||||
}
|
||||
}
|
||||
_, hasContentLength := rws.snapHeader["Content-Length"]
|
||||
if !hasContentLength && clen == "" && rws.handlerDone && bodyAllowedForStatus(rws.status) && (len(p) > 0 || !isHeadResp) {
|
||||
if clen == "" && rws.handlerDone && bodyAllowedForStatus(rws.status) && (len(p) > 0 || !isHeadResp) {
|
||||
clen = strconv.Itoa(len(p))
|
||||
}
|
||||
_, hasContentType := rws.snapHeader["Content-Type"]
|
||||
|
|
@ -2670,6 +2599,7 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
|
|||
date: date,
|
||||
})
|
||||
if err != nil {
|
||||
rws.dirty = true
|
||||
return 0, err
|
||||
}
|
||||
if endStream {
|
||||
|
|
@ -2690,6 +2620,7 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
|
|||
if len(p) > 0 || endStream {
|
||||
// only send a 0 byte DATA frame if we're ending the stream.
|
||||
if err := rws.conn.writeDataFromHandler(rws.stream, p, endStream); err != nil {
|
||||
rws.dirty = true
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
|
@ -2701,6 +2632,9 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
|
|||
trailers: rws.trailers,
|
||||
endStream: true,
|
||||
})
|
||||
if err != nil {
|
||||
rws.dirty = true
|
||||
}
|
||||
return len(p), err
|
||||
}
|
||||
return len(p), nil
|
||||
|
|
@ -2825,7 +2759,7 @@ func (w *responseWriter) FlushError() error {
|
|||
err = rws.bw.Flush()
|
||||
} else {
|
||||
// The bufio.Writer won't call chunkWriter.Write
|
||||
// (writeChunk with zero bytes), so we have to do it
|
||||
// (writeChunk with zero bytes, so we have to do it
|
||||
// ourselves to force the HTTP response header and/or
|
||||
// final DATA frame (with END_STREAM) to be sent.
|
||||
_, err = chunkWriter{rws}.Write(nil)
|
||||
|
|
@ -2916,12 +2850,14 @@ func (rws *responseWriterState) writeHeader(code int) {
|
|||
h.Del("Transfer-Encoding")
|
||||
}
|
||||
|
||||
rws.conn.writeHeaders(rws.stream, &writeResHeaders{
|
||||
if rws.conn.writeHeaders(rws.stream, &writeResHeaders{
|
||||
streamID: rws.stream.id,
|
||||
httpResCode: code,
|
||||
h: h,
|
||||
endStream: rws.handlerDone && !rws.hasTrailers(),
|
||||
})
|
||||
}) != nil {
|
||||
rws.dirty = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
@ -2986,10 +2922,19 @@ func (w *responseWriter) write(lenData int, dataB []byte, dataS string) (n int,
|
|||
|
||||
func (w *responseWriter) handlerDone() {
|
||||
rws := w.rws
|
||||
dirty := rws.dirty
|
||||
rws.handlerDone = true
|
||||
w.Flush()
|
||||
w.rws = nil
|
||||
responseWriterStatePool.Put(rws)
|
||||
if !dirty {
|
||||
// Only recycle the pool if all prior Write calls to
|
||||
// the serverConn goroutine completed successfully. If
|
||||
// they returned earlier due to resets from the peer
|
||||
// there might still be write goroutines outstanding
|
||||
// from the serverConn referencing the rws memory. See
|
||||
// issue 20704.
|
||||
responseWriterStatePool.Put(rws)
|
||||
}
|
||||
}
|
||||
|
||||
// Push errors.
|
||||
|
|
@ -3172,7 +3117,6 @@ func (sc *serverConn) startPush(msg *startPushRequest) {
|
|||
panic(fmt.Sprintf("newWriterAndRequestNoBody(%+v): %v", msg.url, err))
|
||||
}
|
||||
|
||||
sc.curHandlers++
|
||||
go sc.runHandler(rw, req, sc.handler.ServeHTTP)
|
||||
return promisedID, nil
|
||||
}
|
||||
|
|
|
|||
331
vendor/golang.org/x/net/http2/testsync.go
generated
vendored
331
vendor/golang.org/x/net/http2/testsync.go
generated
vendored
|
|
@ -1,331 +0,0 @@
|
|||
// Copyright 2024 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 http2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// testSyncHooks coordinates goroutines in tests.
|
||||
//
|
||||
// For example, a call to ClientConn.RoundTrip involves several goroutines, including:
|
||||
// - the goroutine running RoundTrip;
|
||||
// - the clientStream.doRequest goroutine, which writes the request; and
|
||||
// - the clientStream.readLoop goroutine, which reads the response.
|
||||
//
|
||||
// Using testSyncHooks, a test can start a RoundTrip and identify when all these goroutines
|
||||
// are blocked waiting for some condition such as reading the Request.Body or waiting for
|
||||
// flow control to become available.
|
||||
//
|
||||
// The testSyncHooks also manage timers and synthetic time in tests.
|
||||
// This permits us to, for example, start a request and cause it to time out waiting for
|
||||
// response headers without resorting to time.Sleep calls.
|
||||
type testSyncHooks struct {
|
||||
// active/inactive act as a mutex and condition variable.
|
||||
//
|
||||
// - neither chan contains a value: testSyncHooks is locked.
|
||||
// - active contains a value: unlocked, and at least one goroutine is not blocked
|
||||
// - inactive contains a value: unlocked, and all goroutines are blocked
|
||||
active chan struct{}
|
||||
inactive chan struct{}
|
||||
|
||||
// goroutine counts
|
||||
total int // total goroutines
|
||||
condwait map[*sync.Cond]int // blocked in sync.Cond.Wait
|
||||
blocked []*testBlockedGoroutine // otherwise blocked
|
||||
|
||||
// fake time
|
||||
now time.Time
|
||||
timers []*fakeTimer
|
||||
|
||||
// Transport testing: Report various events.
|
||||
newclientconn func(*ClientConn)
|
||||
newstream func(*clientStream)
|
||||
}
|
||||
|
||||
// testBlockedGoroutine is a blocked goroutine.
|
||||
type testBlockedGoroutine struct {
|
||||
f func() bool // blocked until f returns true
|
||||
ch chan struct{} // closed when unblocked
|
||||
}
|
||||
|
||||
func newTestSyncHooks() *testSyncHooks {
|
||||
h := &testSyncHooks{
|
||||
active: make(chan struct{}, 1),
|
||||
inactive: make(chan struct{}, 1),
|
||||
condwait: map[*sync.Cond]int{},
|
||||
}
|
||||
h.inactive <- struct{}{}
|
||||
h.now = time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
return h
|
||||
}
|
||||
|
||||
// lock acquires the testSyncHooks mutex.
|
||||
func (h *testSyncHooks) lock() {
|
||||
select {
|
||||
case <-h.active:
|
||||
case <-h.inactive:
|
||||
}
|
||||
}
|
||||
|
||||
// waitInactive waits for all goroutines to become inactive.
|
||||
func (h *testSyncHooks) waitInactive() {
|
||||
for {
|
||||
<-h.inactive
|
||||
if !h.unlock() {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unlock releases the testSyncHooks mutex.
|
||||
// It reports whether any goroutines are active.
|
||||
func (h *testSyncHooks) unlock() (active bool) {
|
||||
// Look for a blocked goroutine which can be unblocked.
|
||||
blocked := h.blocked[:0]
|
||||
unblocked := false
|
||||
for _, b := range h.blocked {
|
||||
if !unblocked && b.f() {
|
||||
unblocked = true
|
||||
close(b.ch)
|
||||
} else {
|
||||
blocked = append(blocked, b)
|
||||
}
|
||||
}
|
||||
h.blocked = blocked
|
||||
|
||||
// Count goroutines blocked on condition variables.
|
||||
condwait := 0
|
||||
for _, count := range h.condwait {
|
||||
condwait += count
|
||||
}
|
||||
|
||||
if h.total > condwait+len(blocked) {
|
||||
h.active <- struct{}{}
|
||||
return true
|
||||
} else {
|
||||
h.inactive <- struct{}{}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// goRun starts a new goroutine.
|
||||
func (h *testSyncHooks) goRun(f func()) {
|
||||
h.lock()
|
||||
h.total++
|
||||
h.unlock()
|
||||
go func() {
|
||||
defer func() {
|
||||
h.lock()
|
||||
h.total--
|
||||
h.unlock()
|
||||
}()
|
||||
f()
|
||||
}()
|
||||
}
|
||||
|
||||
// blockUntil indicates that a goroutine is blocked waiting for some condition to become true.
|
||||
// It waits until f returns true before proceeding.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// h.blockUntil(func() bool {
|
||||
// // Is the context done yet?
|
||||
// select {
|
||||
// case <-ctx.Done():
|
||||
// default:
|
||||
// return false
|
||||
// }
|
||||
// return true
|
||||
// })
|
||||
// // Wait for the context to become done.
|
||||
// <-ctx.Done()
|
||||
//
|
||||
// The function f passed to blockUntil must be non-blocking and idempotent.
|
||||
func (h *testSyncHooks) blockUntil(f func() bool) {
|
||||
if f() {
|
||||
return
|
||||
}
|
||||
ch := make(chan struct{})
|
||||
h.lock()
|
||||
h.blocked = append(h.blocked, &testBlockedGoroutine{
|
||||
f: f,
|
||||
ch: ch,
|
||||
})
|
||||
h.unlock()
|
||||
<-ch
|
||||
}
|
||||
|
||||
// broadcast is sync.Cond.Broadcast.
|
||||
func (h *testSyncHooks) condBroadcast(cond *sync.Cond) {
|
||||
h.lock()
|
||||
delete(h.condwait, cond)
|
||||
h.unlock()
|
||||
cond.Broadcast()
|
||||
}
|
||||
|
||||
// broadcast is sync.Cond.Wait.
|
||||
func (h *testSyncHooks) condWait(cond *sync.Cond) {
|
||||
h.lock()
|
||||
h.condwait[cond]++
|
||||
h.unlock()
|
||||
}
|
||||
|
||||
// newTimer creates a new fake timer.
|
||||
func (h *testSyncHooks) newTimer(d time.Duration) timer {
|
||||
h.lock()
|
||||
defer h.unlock()
|
||||
t := &fakeTimer{
|
||||
hooks: h,
|
||||
when: h.now.Add(d),
|
||||
c: make(chan time.Time),
|
||||
}
|
||||
h.timers = append(h.timers, t)
|
||||
return t
|
||||
}
|
||||
|
||||
// afterFunc creates a new fake AfterFunc timer.
|
||||
func (h *testSyncHooks) afterFunc(d time.Duration, f func()) timer {
|
||||
h.lock()
|
||||
defer h.unlock()
|
||||
t := &fakeTimer{
|
||||
hooks: h,
|
||||
when: h.now.Add(d),
|
||||
f: f,
|
||||
}
|
||||
h.timers = append(h.timers, t)
|
||||
return t
|
||||
}
|
||||
|
||||
func (h *testSyncHooks) contextWithTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
t := h.afterFunc(d, cancel)
|
||||
return ctx, func() {
|
||||
t.Stop()
|
||||
cancel()
|
||||
}
|
||||
}
|
||||
|
||||
func (h *testSyncHooks) timeUntilEvent() time.Duration {
|
||||
h.lock()
|
||||
defer h.unlock()
|
||||
var next time.Time
|
||||
for _, t := range h.timers {
|
||||
if next.IsZero() || t.when.Before(next) {
|
||||
next = t.when
|
||||
}
|
||||
}
|
||||
if d := next.Sub(h.now); d > 0 {
|
||||
return d
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// advance advances time and causes synthetic timers to fire.
|
||||
func (h *testSyncHooks) advance(d time.Duration) {
|
||||
h.lock()
|
||||
defer h.unlock()
|
||||
h.now = h.now.Add(d)
|
||||
timers := h.timers[:0]
|
||||
for _, t := range h.timers {
|
||||
t := t // remove after go.mod depends on go1.22
|
||||
t.mu.Lock()
|
||||
switch {
|
||||
case t.when.After(h.now):
|
||||
timers = append(timers, t)
|
||||
case t.when.IsZero():
|
||||
// stopped timer
|
||||
default:
|
||||
t.when = time.Time{}
|
||||
if t.c != nil {
|
||||
close(t.c)
|
||||
}
|
||||
if t.f != nil {
|
||||
h.total++
|
||||
go func() {
|
||||
defer func() {
|
||||
h.lock()
|
||||
h.total--
|
||||
h.unlock()
|
||||
}()
|
||||
t.f()
|
||||
}()
|
||||
}
|
||||
}
|
||||
t.mu.Unlock()
|
||||
}
|
||||
h.timers = timers
|
||||
}
|
||||
|
||||
// A timer wraps a time.Timer, or a synthetic equivalent in tests.
|
||||
// Unlike time.Timer, timer is single-use: The timer channel is closed when the timer expires.
|
||||
type timer interface {
|
||||
C() <-chan time.Time
|
||||
Stop() bool
|
||||
Reset(d time.Duration) bool
|
||||
}
|
||||
|
||||
// timeTimer implements timer using real time.
|
||||
type timeTimer struct {
|
||||
t *time.Timer
|
||||
c chan time.Time
|
||||
}
|
||||
|
||||
// newTimeTimer creates a new timer using real time.
|
||||
func newTimeTimer(d time.Duration) timer {
|
||||
ch := make(chan time.Time)
|
||||
t := time.AfterFunc(d, func() {
|
||||
close(ch)
|
||||
})
|
||||
return &timeTimer{t, ch}
|
||||
}
|
||||
|
||||
// newTimeAfterFunc creates an AfterFunc timer using real time.
|
||||
func newTimeAfterFunc(d time.Duration, f func()) timer {
|
||||
return &timeTimer{
|
||||
t: time.AfterFunc(d, f),
|
||||
}
|
||||
}
|
||||
|
||||
func (t timeTimer) C() <-chan time.Time { return t.c }
|
||||
func (t timeTimer) Stop() bool { return t.t.Stop() }
|
||||
func (t timeTimer) Reset(d time.Duration) bool { return t.t.Reset(d) }
|
||||
|
||||
// fakeTimer implements timer using fake time.
|
||||
type fakeTimer struct {
|
||||
hooks *testSyncHooks
|
||||
|
||||
mu sync.Mutex
|
||||
when time.Time // when the timer will fire
|
||||
c chan time.Time // closed when the timer fires; mutually exclusive with f
|
||||
f func() // called when the timer fires; mutually exclusive with c
|
||||
}
|
||||
|
||||
func (t *fakeTimer) C() <-chan time.Time { return t.c }
|
||||
|
||||
func (t *fakeTimer) Stop() bool {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
stopped := t.when.IsZero()
|
||||
t.when = time.Time{}
|
||||
return stopped
|
||||
}
|
||||
|
||||
func (t *fakeTimer) Reset(d time.Duration) bool {
|
||||
if t.c != nil || t.f == nil {
|
||||
panic("fakeTimer only supports Reset on AfterFunc timers")
|
||||
}
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
t.hooks.lock()
|
||||
defer t.hooks.unlock()
|
||||
active := !t.when.IsZero()
|
||||
t.when = t.hooks.now.Add(d)
|
||||
if !active {
|
||||
t.hooks.timers = append(t.hooks.timers, t)
|
||||
}
|
||||
return active
|
||||
}
|
||||
436
vendor/golang.org/x/net/http2/transport.go
generated
vendored
436
vendor/golang.org/x/net/http2/transport.go
generated
vendored
|
|
@ -19,7 +19,6 @@ import (
|
|||
"io/fs"
|
||||
"log"
|
||||
"math"
|
||||
"math/bits"
|
||||
mathrand "math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
|
|
@ -147,12 +146,6 @@ type Transport struct {
|
|||
// waiting for their turn.
|
||||
StrictMaxConcurrentStreams bool
|
||||
|
||||
// IdleConnTimeout is the maximum amount of time an idle
|
||||
// (keep-alive) connection will remain idle before closing
|
||||
// itself.
|
||||
// Zero means no limit.
|
||||
IdleConnTimeout time.Duration
|
||||
|
||||
// ReadIdleTimeout is the timeout after which a health check using ping
|
||||
// frame will be carried out if no frame is received on the connection.
|
||||
// Note that a ping response will is considered a received frame, so if
|
||||
|
|
@ -184,8 +177,6 @@ type Transport struct {
|
|||
|
||||
connPoolOnce sync.Once
|
||||
connPoolOrDef ClientConnPool // non-nil version of ConnPool
|
||||
|
||||
syncHooks *testSyncHooks
|
||||
}
|
||||
|
||||
func (t *Transport) maxHeaderListSize() uint32 {
|
||||
|
|
@ -299,7 +290,8 @@ func (t *Transport) initConnPool() {
|
|||
// HTTP/2 server.
|
||||
type ClientConn struct {
|
||||
t *Transport
|
||||
tconn net.Conn // usually *tls.Conn, except specialized impls
|
||||
tconn net.Conn // usually *tls.Conn, except specialized impls
|
||||
tconnClosed bool
|
||||
tlsState *tls.ConnectionState // nil only for specialized impls
|
||||
reused uint32 // whether conn is being reused; atomic
|
||||
singleUse bool // whether being used for a single http.Request
|
||||
|
|
@ -310,7 +302,7 @@ type ClientConn struct {
|
|||
readerErr error // set before readerDone is closed
|
||||
|
||||
idleTimeout time.Duration // or 0 for never
|
||||
idleTimer timer
|
||||
idleTimer *time.Timer
|
||||
|
||||
mu sync.Mutex // guards following
|
||||
cond *sync.Cond // hold mu; broadcast on flow/closed changes
|
||||
|
|
@ -352,60 +344,6 @@ type ClientConn struct {
|
|||
werr error // first write error that has occurred
|
||||
hbuf bytes.Buffer // HPACK encoder writes into this
|
||||
henc *hpack.Encoder
|
||||
|
||||
syncHooks *testSyncHooks // can be nil
|
||||
}
|
||||
|
||||
// Hook points used for testing.
|
||||
// Outside of tests, cc.syncHooks is nil and these all have minimal implementations.
|
||||
// Inside tests, see the testSyncHooks function docs.
|
||||
|
||||
// goRun starts a new goroutine.
|
||||
func (cc *ClientConn) goRun(f func()) {
|
||||
if cc.syncHooks != nil {
|
||||
cc.syncHooks.goRun(f)
|
||||
return
|
||||
}
|
||||
go f()
|
||||
}
|
||||
|
||||
// condBroadcast is cc.cond.Broadcast.
|
||||
func (cc *ClientConn) condBroadcast() {
|
||||
if cc.syncHooks != nil {
|
||||
cc.syncHooks.condBroadcast(cc.cond)
|
||||
}
|
||||
cc.cond.Broadcast()
|
||||
}
|
||||
|
||||
// condWait is cc.cond.Wait.
|
||||
func (cc *ClientConn) condWait() {
|
||||
if cc.syncHooks != nil {
|
||||
cc.syncHooks.condWait(cc.cond)
|
||||
}
|
||||
cc.cond.Wait()
|
||||
}
|
||||
|
||||
// newTimer creates a new time.Timer, or a synthetic timer in tests.
|
||||
func (cc *ClientConn) newTimer(d time.Duration) timer {
|
||||
if cc.syncHooks != nil {
|
||||
return cc.syncHooks.newTimer(d)
|
||||
}
|
||||
return newTimeTimer(d)
|
||||
}
|
||||
|
||||
// afterFunc creates a new time.AfterFunc timer, or a synthetic timer in tests.
|
||||
func (cc *ClientConn) afterFunc(d time.Duration, f func()) timer {
|
||||
if cc.syncHooks != nil {
|
||||
return cc.syncHooks.afterFunc(d, f)
|
||||
}
|
||||
return newTimeAfterFunc(d, f)
|
||||
}
|
||||
|
||||
func (cc *ClientConn) contextWithTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc) {
|
||||
if cc.syncHooks != nil {
|
||||
return cc.syncHooks.contextWithTimeout(ctx, d)
|
||||
}
|
||||
return context.WithTimeout(ctx, d)
|
||||
}
|
||||
|
||||
// clientStream is the state for a single HTTP/2 stream. One of these
|
||||
|
|
@ -487,7 +425,7 @@ func (cs *clientStream) abortStreamLocked(err error) {
|
|||
// TODO(dneil): Clean up tests where cs.cc.cond is nil.
|
||||
if cs.cc.cond != nil {
|
||||
// Wake up writeRequestBody if it is waiting on flow control.
|
||||
cs.cc.condBroadcast()
|
||||
cs.cc.cond.Broadcast()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -497,7 +435,7 @@ func (cs *clientStream) abortRequestBodyWrite() {
|
|||
defer cc.mu.Unlock()
|
||||
if cs.reqBody != nil && cs.reqBodyClosed == nil {
|
||||
cs.closeReqBodyLocked()
|
||||
cc.condBroadcast()
|
||||
cc.cond.Broadcast()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -507,10 +445,10 @@ func (cs *clientStream) closeReqBodyLocked() {
|
|||
}
|
||||
cs.reqBodyClosed = make(chan struct{})
|
||||
reqBodyClosed := cs.reqBodyClosed
|
||||
cs.cc.goRun(func() {
|
||||
go func() {
|
||||
cs.reqBody.Close()
|
||||
close(reqBodyClosed)
|
||||
})
|
||||
}()
|
||||
}
|
||||
|
||||
type stickyErrWriter struct {
|
||||
|
|
@ -580,14 +518,11 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|||
func authorityAddr(scheme string, authority string) (addr string) {
|
||||
host, port, err := net.SplitHostPort(authority)
|
||||
if err != nil { // authority didn't have a port
|
||||
host = authority
|
||||
port = ""
|
||||
}
|
||||
if port == "" { // authority's port was empty
|
||||
port = "443"
|
||||
if scheme == "http" {
|
||||
port = "80"
|
||||
}
|
||||
host = authority
|
||||
}
|
||||
if a, err := idna.ToASCII(host); err == nil {
|
||||
host = a
|
||||
|
|
@ -599,6 +534,15 @@ func authorityAddr(scheme string, authority string) (addr string) {
|
|||
return net.JoinHostPort(host, port)
|
||||
}
|
||||
|
||||
var retryBackoffHook func(time.Duration) *time.Timer
|
||||
|
||||
func backoffNewTimer(d time.Duration) *time.Timer {
|
||||
if retryBackoffHook != nil {
|
||||
return retryBackoffHook(d)
|
||||
}
|
||||
return time.NewTimer(d)
|
||||
}
|
||||
|
||||
// RoundTripOpt is like RoundTrip, but takes options.
|
||||
func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Response, error) {
|
||||
if !(req.URL.Scheme == "https" || (req.URL.Scheme == "http" && t.AllowHTTP)) {
|
||||
|
|
@ -616,37 +560,22 @@ func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res
|
|||
traceGotConn(req, cc, reused)
|
||||
res, err := cc.RoundTrip(req)
|
||||
if err != nil && retry <= 6 {
|
||||
roundTripErr := err
|
||||
if req, err = shouldRetryRequest(req, err); err == nil {
|
||||
// After the first retry, do exponential backoff with 10% jitter.
|
||||
if retry == 0 {
|
||||
t.vlogf("RoundTrip retrying after failure: %v", roundTripErr)
|
||||
t.vlogf("RoundTrip retrying after failure: %v", err)
|
||||
continue
|
||||
}
|
||||
backoff := float64(uint(1) << (uint(retry) - 1))
|
||||
backoff += backoff * (0.1 * mathrand.Float64())
|
||||
d := time.Second * time.Duration(backoff)
|
||||
var tm timer
|
||||
if t.syncHooks != nil {
|
||||
tm = t.syncHooks.newTimer(d)
|
||||
t.syncHooks.blockUntil(func() bool {
|
||||
select {
|
||||
case <-tm.C():
|
||||
case <-req.Context().Done():
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
} else {
|
||||
tm = newTimeTimer(d)
|
||||
}
|
||||
timer := backoffNewTimer(d)
|
||||
select {
|
||||
case <-tm.C():
|
||||
t.vlogf("RoundTrip retrying after failure: %v", roundTripErr)
|
||||
case <-timer.C:
|
||||
t.vlogf("RoundTrip retrying after failure: %v", err)
|
||||
continue
|
||||
case <-req.Context().Done():
|
||||
tm.Stop()
|
||||
timer.Stop()
|
||||
err = req.Context().Err()
|
||||
}
|
||||
}
|
||||
|
|
@ -725,9 +654,6 @@ func canRetryError(err error) bool {
|
|||
}
|
||||
|
||||
func (t *Transport) dialClientConn(ctx context.Context, addr string, singleUse bool) (*ClientConn, error) {
|
||||
if t.syncHooks != nil {
|
||||
return t.newClientConn(nil, singleUse, t.syncHooks)
|
||||
}
|
||||
host, _, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -736,7 +662,7 @@ func (t *Transport) dialClientConn(ctx context.Context, addr string, singleUse b
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return t.newClientConn(tconn, singleUse, nil)
|
||||
return t.newClientConn(tconn, singleUse)
|
||||
}
|
||||
|
||||
func (t *Transport) newTLSConfig(host string) *tls.Config {
|
||||
|
|
@ -802,10 +728,10 @@ func (t *Transport) maxEncoderHeaderTableSize() uint32 {
|
|||
}
|
||||
|
||||
func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
|
||||
return t.newClientConn(c, t.disableKeepAlives(), nil)
|
||||
return t.newClientConn(c, t.disableKeepAlives())
|
||||
}
|
||||
|
||||
func (t *Transport) newClientConn(c net.Conn, singleUse bool, hooks *testSyncHooks) (*ClientConn, error) {
|
||||
func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, error) {
|
||||
cc := &ClientConn{
|
||||
t: t,
|
||||
tconn: c,
|
||||
|
|
@ -820,15 +746,10 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool, hooks *testSyncHoo
|
|||
wantSettingsAck: true,
|
||||
pings: make(map[[8]byte]chan struct{}),
|
||||
reqHeaderMu: make(chan struct{}, 1),
|
||||
syncHooks: hooks,
|
||||
}
|
||||
if hooks != nil {
|
||||
hooks.newclientconn(cc)
|
||||
c = cc.tconn
|
||||
}
|
||||
if d := t.idleConnTimeout(); d != 0 {
|
||||
cc.idleTimeout = d
|
||||
cc.idleTimer = cc.afterFunc(d, cc.onIdleTimeout)
|
||||
cc.idleTimer = time.AfterFunc(d, cc.onIdleTimeout)
|
||||
}
|
||||
if VerboseLogs {
|
||||
t.vlogf("http2: Transport creating client conn %p to %v", cc, c.RemoteAddr())
|
||||
|
|
@ -893,7 +814,7 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool, hooks *testSyncHoo
|
|||
return nil, cc.werr
|
||||
}
|
||||
|
||||
cc.goRun(cc.readLoop)
|
||||
go cc.readLoop()
|
||||
return cc, nil
|
||||
}
|
||||
|
||||
|
|
@ -901,7 +822,7 @@ func (cc *ClientConn) healthCheck() {
|
|||
pingTimeout := cc.t.pingTimeout()
|
||||
// We don't need to periodically ping in the health check, because the readLoop of ClientConn will
|
||||
// trigger the healthCheck again if there is no frame received.
|
||||
ctx, cancel := cc.contextWithTimeout(context.Background(), pingTimeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), pingTimeout)
|
||||
defer cancel()
|
||||
cc.vlogf("http2: Transport sending health check")
|
||||
err := cc.Ping(ctx)
|
||||
|
|
@ -936,20 +857,7 @@ func (cc *ClientConn) setGoAway(f *GoAwayFrame) {
|
|||
}
|
||||
last := f.LastStreamID
|
||||
for streamID, cs := range cc.streams {
|
||||
if streamID <= last {
|
||||
// The server's GOAWAY indicates that it received this stream.
|
||||
// It will either finish processing it, or close the connection
|
||||
// without doing so. Either way, leave the stream alone for now.
|
||||
continue
|
||||
}
|
||||
if streamID == 1 && cc.goAway.ErrCode != ErrCodeNo {
|
||||
// Don't retry the first stream on a connection if we get a non-NO error.
|
||||
// If the server is sending an error on a new connection,
|
||||
// retrying the request on a new one probably isn't going to work.
|
||||
cs.abortStreamLocked(fmt.Errorf("http2: Transport received GOAWAY from server ErrCode:%v", cc.goAway.ErrCode))
|
||||
} else {
|
||||
// Aborting the stream with errClentConnGotGoAway indicates that
|
||||
// the request should be retried on a new connection.
|
||||
if streamID > last {
|
||||
cs.abortStreamLocked(errClientConnGotGoAway)
|
||||
}
|
||||
}
|
||||
|
|
@ -1106,7 +1014,7 @@ func (cc *ClientConn) forceCloseConn() {
|
|||
if !ok {
|
||||
return
|
||||
}
|
||||
if nc := tc.NetConn(); nc != nil {
|
||||
if nc := tlsUnderlyingConn(tc); nc != nil {
|
||||
nc.Close()
|
||||
}
|
||||
}
|
||||
|
|
@ -1144,7 +1052,7 @@ func (cc *ClientConn) Shutdown(ctx context.Context) error {
|
|||
// Wait for all in-flight streams to complete or connection to close
|
||||
done := make(chan struct{})
|
||||
cancelled := false // guarded by cc.mu
|
||||
cc.goRun(func() {
|
||||
go func() {
|
||||
cc.mu.Lock()
|
||||
defer cc.mu.Unlock()
|
||||
for {
|
||||
|
|
@ -1156,9 +1064,9 @@ func (cc *ClientConn) Shutdown(ctx context.Context) error {
|
|||
if cancelled {
|
||||
break
|
||||
}
|
||||
cc.condWait()
|
||||
cc.cond.Wait()
|
||||
}
|
||||
})
|
||||
}()
|
||||
shutdownEnterWaitStateHook()
|
||||
select {
|
||||
case <-done:
|
||||
|
|
@ -1168,7 +1076,7 @@ func (cc *ClientConn) Shutdown(ctx context.Context) error {
|
|||
cc.mu.Lock()
|
||||
// Free the goroutine above
|
||||
cancelled = true
|
||||
cc.condBroadcast()
|
||||
cc.cond.Broadcast()
|
||||
cc.mu.Unlock()
|
||||
return ctx.Err()
|
||||
}
|
||||
|
|
@ -1206,7 +1114,7 @@ func (cc *ClientConn) closeForError(err error) {
|
|||
for _, cs := range cc.streams {
|
||||
cs.abortStreamLocked(err)
|
||||
}
|
||||
cc.condBroadcast()
|
||||
cc.cond.Broadcast()
|
||||
cc.mu.Unlock()
|
||||
cc.closeConn()
|
||||
}
|
||||
|
|
@ -1303,10 +1211,6 @@ func (cc *ClientConn) decrStreamReservationsLocked() {
|
|||
}
|
||||
|
||||
func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return cc.roundTrip(req, nil)
|
||||
}
|
||||
|
||||
func (cc *ClientConn) roundTrip(req *http.Request, streamf func(*clientStream)) (*http.Response, error) {
|
||||
ctx := req.Context()
|
||||
cs := &clientStream{
|
||||
cc: cc,
|
||||
|
|
@ -1321,23 +1225,9 @@ func (cc *ClientConn) roundTrip(req *http.Request, streamf func(*clientStream))
|
|||
respHeaderRecv: make(chan struct{}),
|
||||
donec: make(chan struct{}),
|
||||
}
|
||||
cc.goRun(func() {
|
||||
cs.doRequest(req)
|
||||
})
|
||||
go cs.doRequest(req)
|
||||
|
||||
waitDone := func() error {
|
||||
if cc.syncHooks != nil {
|
||||
cc.syncHooks.blockUntil(func() bool {
|
||||
select {
|
||||
case <-cs.donec:
|
||||
case <-ctx.Done():
|
||||
case <-cs.reqCancel:
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
select {
|
||||
case <-cs.donec:
|
||||
return nil
|
||||
|
|
@ -1375,47 +1265,7 @@ func (cc *ClientConn) roundTrip(req *http.Request, streamf func(*clientStream))
|
|||
return res, nil
|
||||
}
|
||||
|
||||
cancelRequest := func(cs *clientStream, err error) error {
|
||||
cs.cc.mu.Lock()
|
||||
bodyClosed := cs.reqBodyClosed
|
||||
cs.cc.mu.Unlock()
|
||||
// Wait for the request body to be closed.
|
||||
//
|
||||
// If nothing closed the body before now, abortStreamLocked
|
||||
// will have started a goroutine to close it.
|
||||
//
|
||||
// Closing the body before returning avoids a race condition
|
||||
// with net/http checking its readTrackingBody to see if the
|
||||
// body was read from or closed. See golang/go#60041.
|
||||
//
|
||||
// The body is closed in a separate goroutine without the
|
||||
// connection mutex held, but dropping the mutex before waiting
|
||||
// will keep us from holding it indefinitely if the body
|
||||
// close is slow for some reason.
|
||||
if bodyClosed != nil {
|
||||
<-bodyClosed
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if streamf != nil {
|
||||
streamf(cs)
|
||||
}
|
||||
|
||||
for {
|
||||
if cc.syncHooks != nil {
|
||||
cc.syncHooks.blockUntil(func() bool {
|
||||
select {
|
||||
case <-cs.respHeaderRecv:
|
||||
case <-cs.abort:
|
||||
case <-ctx.Done():
|
||||
case <-cs.reqCancel:
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
select {
|
||||
case <-cs.respHeaderRecv:
|
||||
return handleResponseHeaders()
|
||||
|
|
@ -1434,10 +1284,10 @@ func (cc *ClientConn) roundTrip(req *http.Request, streamf func(*clientStream))
|
|||
case <-ctx.Done():
|
||||
err := ctx.Err()
|
||||
cs.abortStream(err)
|
||||
return nil, cancelRequest(cs, err)
|
||||
return nil, err
|
||||
case <-cs.reqCancel:
|
||||
cs.abortStream(errRequestCanceled)
|
||||
return nil, cancelRequest(cs, errRequestCanceled)
|
||||
return nil, errRequestCanceled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1471,21 +1321,6 @@ func (cs *clientStream) writeRequest(req *http.Request) (err error) {
|
|||
if cc.reqHeaderMu == nil {
|
||||
panic("RoundTrip on uninitialized ClientConn") // for tests
|
||||
}
|
||||
var newStreamHook func(*clientStream)
|
||||
if cc.syncHooks != nil {
|
||||
newStreamHook = cc.syncHooks.newstream
|
||||
cc.syncHooks.blockUntil(func() bool {
|
||||
select {
|
||||
case cc.reqHeaderMu <- struct{}{}:
|
||||
<-cc.reqHeaderMu
|
||||
case <-cs.reqCancel:
|
||||
case <-ctx.Done():
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
select {
|
||||
case cc.reqHeaderMu <- struct{}{}:
|
||||
case <-cs.reqCancel:
|
||||
|
|
@ -1510,10 +1345,6 @@ func (cs *clientStream) writeRequest(req *http.Request) (err error) {
|
|||
}
|
||||
cc.mu.Unlock()
|
||||
|
||||
if newStreamHook != nil {
|
||||
newStreamHook(cs)
|
||||
}
|
||||
|
||||
// TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere?
|
||||
if !cc.t.disableCompression() &&
|
||||
req.Header.Get("Accept-Encoding") == "" &&
|
||||
|
|
@ -1594,30 +1425,15 @@ func (cs *clientStream) writeRequest(req *http.Request) (err error) {
|
|||
var respHeaderTimer <-chan time.Time
|
||||
var respHeaderRecv chan struct{}
|
||||
if d := cc.responseHeaderTimeout(); d != 0 {
|
||||
timer := cc.newTimer(d)
|
||||
timer := time.NewTimer(d)
|
||||
defer timer.Stop()
|
||||
respHeaderTimer = timer.C()
|
||||
respHeaderTimer = timer.C
|
||||
respHeaderRecv = cs.respHeaderRecv
|
||||
}
|
||||
// Wait until the peer half-closes its end of the stream,
|
||||
// or until the request is aborted (via context, error, or otherwise),
|
||||
// whichever comes first.
|
||||
for {
|
||||
if cc.syncHooks != nil {
|
||||
cc.syncHooks.blockUntil(func() bool {
|
||||
select {
|
||||
case <-cs.peerClosed:
|
||||
case <-respHeaderTimer:
|
||||
case <-respHeaderRecv:
|
||||
case <-cs.abort:
|
||||
case <-ctx.Done():
|
||||
case <-cs.reqCancel:
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
select {
|
||||
case <-cs.peerClosed:
|
||||
return nil
|
||||
|
|
@ -1766,7 +1582,7 @@ func (cc *ClientConn) awaitOpenSlotForStreamLocked(cs *clientStream) error {
|
|||
return nil
|
||||
}
|
||||
cc.pendingRequests++
|
||||
cc.condWait()
|
||||
cc.cond.Wait()
|
||||
cc.pendingRequests--
|
||||
select {
|
||||
case <-cs.abort:
|
||||
|
|
@ -1837,27 +1653,7 @@ func (cs *clientStream) frameScratchBufferLen(maxFrameSize int) int {
|
|||
return int(n) // doesn't truncate; max is 512K
|
||||
}
|
||||
|
||||
// Seven bufPools manage different frame sizes. This helps to avoid scenarios where long-running
|
||||
// streaming requests using small frame sizes occupy large buffers initially allocated for prior
|
||||
// requests needing big buffers. The size ranges are as follows:
|
||||
// {0 KB, 16 KB], {16 KB, 32 KB], {32 KB, 64 KB], {64 KB, 128 KB], {128 KB, 256 KB],
|
||||
// {256 KB, 512 KB], {512 KB, infinity}
|
||||
// In practice, the maximum scratch buffer size should not exceed 512 KB due to
|
||||
// frameScratchBufferLen(maxFrameSize), thus the "infinity pool" should never be used.
|
||||
// It exists mainly as a safety measure, for potential future increases in max buffer size.
|
||||
var bufPools [7]sync.Pool // of *[]byte
|
||||
func bufPoolIndex(size int) int {
|
||||
if size <= 16384 {
|
||||
return 0
|
||||
}
|
||||
size -= 1
|
||||
bits := bits.Len(uint(size))
|
||||
index := bits - 14
|
||||
if index >= len(bufPools) {
|
||||
return len(bufPools) - 1
|
||||
}
|
||||
return index
|
||||
}
|
||||
var bufPool sync.Pool // of *[]byte
|
||||
|
||||
func (cs *clientStream) writeRequestBody(req *http.Request) (err error) {
|
||||
cc := cs.cc
|
||||
|
|
@ -1875,13 +1671,12 @@ func (cs *clientStream) writeRequestBody(req *http.Request) (err error) {
|
|||
// Scratch buffer for reading into & writing from.
|
||||
scratchLen := cs.frameScratchBufferLen(maxFrameSize)
|
||||
var buf []byte
|
||||
index := bufPoolIndex(scratchLen)
|
||||
if bp, ok := bufPools[index].Get().(*[]byte); ok && len(*bp) >= scratchLen {
|
||||
defer bufPools[index].Put(bp)
|
||||
if bp, ok := bufPool.Get().(*[]byte); ok && len(*bp) >= scratchLen {
|
||||
defer bufPool.Put(bp)
|
||||
buf = *bp
|
||||
} else {
|
||||
buf = make([]byte, scratchLen)
|
||||
defer bufPools[index].Put(&buf)
|
||||
defer bufPool.Put(&buf)
|
||||
}
|
||||
|
||||
var sawEOF bool
|
||||
|
|
@ -2028,26 +1823,10 @@ func (cs *clientStream) awaitFlowControl(maxBytes int) (taken int32, err error)
|
|||
cs.flow.take(take)
|
||||
return take, nil
|
||||
}
|
||||
cc.condWait()
|
||||
cc.cond.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
func validateHeaders(hdrs http.Header) string {
|
||||
for k, vv := range hdrs {
|
||||
if !httpguts.ValidHeaderFieldName(k) {
|
||||
return fmt.Sprintf("name %q", k)
|
||||
}
|
||||
for _, v := range vv {
|
||||
if !httpguts.ValidHeaderFieldValue(v) {
|
||||
// Don't include the value in the error,
|
||||
// because it may be sensitive.
|
||||
return fmt.Sprintf("value for header %q", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var errNilRequestURL = errors.New("http2: Request.URI is nil")
|
||||
|
||||
// requires cc.wmu be held.
|
||||
|
|
@ -2065,9 +1844,6 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !httpguts.ValidHostHeader(host) {
|
||||
return nil, errors.New("http2: invalid Host header")
|
||||
}
|
||||
|
||||
var path string
|
||||
if req.Method != "CONNECT" {
|
||||
|
|
@ -2085,21 +1861,26 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail
|
|||
}
|
||||
}
|
||||
|
||||
// Check for any invalid headers+trailers and return an error before we
|
||||
// Check for any invalid headers and return an error before we
|
||||
// potentially pollute our hpack state. (We want to be able to
|
||||
// continue to reuse the hpack encoder for future requests)
|
||||
if err := validateHeaders(req.Header); err != "" {
|
||||
return nil, fmt.Errorf("invalid HTTP header %s", err)
|
||||
}
|
||||
if err := validateHeaders(req.Trailer); err != "" {
|
||||
return nil, fmt.Errorf("invalid HTTP trailer %s", err)
|
||||
for k, vv := range req.Header {
|
||||
if !httpguts.ValidHeaderFieldName(k) {
|
||||
return nil, fmt.Errorf("invalid HTTP header name %q", k)
|
||||
}
|
||||
for _, v := range vv {
|
||||
if !httpguts.ValidHeaderFieldValue(v) {
|
||||
// Don't include the value in the error, because it may be sensitive.
|
||||
return nil, fmt.Errorf("invalid HTTP header value for header %q", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enumerateHeaders := func(f func(name, value string)) {
|
||||
// 8.1.2.3 Request Pseudo-Header Fields
|
||||
// The :path pseudo-header field includes the path and query parts of the
|
||||
// target URI (the path-absolute production and optionally a '?' character
|
||||
// followed by the query production, see Sections 3.3 and 3.4 of
|
||||
// followed by the query production (see Sections 3.3 and 3.4 of
|
||||
// [RFC3986]).
|
||||
f(":authority", host)
|
||||
m := req.Method
|
||||
|
|
@ -2311,7 +2092,7 @@ func (cc *ClientConn) forgetStreamID(id uint32) {
|
|||
}
|
||||
// Wake up writeRequestBody via clientStream.awaitFlowControl and
|
||||
// wake up RoundTrip if there is a pending request.
|
||||
cc.condBroadcast()
|
||||
cc.cond.Broadcast()
|
||||
|
||||
closeOnIdle := cc.singleUse || cc.doNotReuse || cc.t.disableKeepAlives() || cc.goAway != nil
|
||||
if closeOnIdle && cc.streamsReserved == 0 && len(cc.streams) == 0 {
|
||||
|
|
@ -2399,7 +2180,7 @@ func (rl *clientConnReadLoop) cleanup() {
|
|||
cs.abortStreamLocked(err)
|
||||
}
|
||||
}
|
||||
cc.condBroadcast()
|
||||
cc.cond.Broadcast()
|
||||
cc.mu.Unlock()
|
||||
}
|
||||
|
||||
|
|
@ -2434,9 +2215,10 @@ func (rl *clientConnReadLoop) run() error {
|
|||
cc := rl.cc
|
||||
gotSettings := false
|
||||
readIdleTimeout := cc.t.ReadIdleTimeout
|
||||
var t timer
|
||||
var t *time.Timer
|
||||
if readIdleTimeout != 0 {
|
||||
t = cc.afterFunc(readIdleTimeout, cc.healthCheck)
|
||||
t = time.AfterFunc(readIdleTimeout, cc.healthCheck)
|
||||
defer t.Stop()
|
||||
}
|
||||
for {
|
||||
f, err := cc.fr.ReadFrame()
|
||||
|
|
@ -2773,9 +2555,6 @@ func (b transportResponseBody) Close() error {
|
|||
cs := b.cs
|
||||
cc := cs.cc
|
||||
|
||||
cs.bufPipe.BreakWithError(errClosedResponseBody)
|
||||
cs.abortStream(errClosedResponseBody)
|
||||
|
||||
unread := cs.bufPipe.Len()
|
||||
if unread > 0 {
|
||||
cc.mu.Lock()
|
||||
|
|
@ -2794,6 +2573,9 @@ func (b transportResponseBody) Close() error {
|
|||
cc.wmu.Unlock()
|
||||
}
|
||||
|
||||
cs.bufPipe.BreakWithError(errClosedResponseBody)
|
||||
cs.abortStream(errClosedResponseBody)
|
||||
|
||||
select {
|
||||
case <-cs.donec:
|
||||
case <-cs.ctx.Done():
|
||||
|
|
@ -2851,7 +2633,7 @@ func (rl *clientConnReadLoop) processData(f *DataFrame) error {
|
|||
})
|
||||
return nil
|
||||
}
|
||||
if !cs.pastHeaders {
|
||||
if !cs.firstByte {
|
||||
cc.logf("protocol error: received DATA before a HEADERS frame")
|
||||
rl.endStreamError(cs, StreamError{
|
||||
StreamID: f.StreamID,
|
||||
|
|
@ -3034,7 +2816,7 @@ func (rl *clientConnReadLoop) processSettingsNoWrite(f *SettingsFrame) error {
|
|||
for _, cs := range cc.streams {
|
||||
cs.flow.add(delta)
|
||||
}
|
||||
cc.condBroadcast()
|
||||
cc.cond.Broadcast()
|
||||
|
||||
cc.initialWindowSize = s.Val
|
||||
case SettingHeaderTableSize:
|
||||
|
|
@ -3078,18 +2860,9 @@ func (rl *clientConnReadLoop) processWindowUpdate(f *WindowUpdateFrame) error {
|
|||
fl = &cs.flow
|
||||
}
|
||||
if !fl.add(int32(f.Increment)) {
|
||||
// For stream, the sender sends RST_STREAM with an error code of FLOW_CONTROL_ERROR
|
||||
if cs != nil {
|
||||
rl.endStreamError(cs, StreamError{
|
||||
StreamID: f.StreamID,
|
||||
Code: ErrCodeFlowControl,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
return ConnectionError(ErrCodeFlowControl)
|
||||
}
|
||||
cc.condBroadcast()
|
||||
cc.cond.Broadcast()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -3131,38 +2904,24 @@ func (cc *ClientConn) Ping(ctx context.Context) error {
|
|||
}
|
||||
cc.mu.Unlock()
|
||||
}
|
||||
var pingError error
|
||||
errc := make(chan struct{})
|
||||
cc.goRun(func() {
|
||||
errc := make(chan error, 1)
|
||||
go func() {
|
||||
cc.wmu.Lock()
|
||||
defer cc.wmu.Unlock()
|
||||
if pingError = cc.fr.WritePing(false, p); pingError != nil {
|
||||
close(errc)
|
||||
if err := cc.fr.WritePing(false, p); err != nil {
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
if pingError = cc.bw.Flush(); pingError != nil {
|
||||
close(errc)
|
||||
if err := cc.bw.Flush(); err != nil {
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
})
|
||||
if cc.syncHooks != nil {
|
||||
cc.syncHooks.blockUntil(func() bool {
|
||||
select {
|
||||
case <-c:
|
||||
case <-errc:
|
||||
case <-ctx.Done():
|
||||
case <-cc.readerDone:
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
}()
|
||||
select {
|
||||
case <-c:
|
||||
return nil
|
||||
case <-errc:
|
||||
return pingError
|
||||
case err := <-errc:
|
||||
return err
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-cc.readerDone:
|
||||
|
|
@ -3331,17 +3090,9 @@ func (rt noDialH2RoundTripper) RoundTrip(req *http.Request) (*http.Response, err
|
|||
}
|
||||
|
||||
func (t *Transport) idleConnTimeout() time.Duration {
|
||||
// to keep things backwards compatible, we use non-zero values of
|
||||
// IdleConnTimeout, followed by using the IdleConnTimeout on the underlying
|
||||
// http1 transport, followed by 0
|
||||
if t.IdleConnTimeout != 0 {
|
||||
return t.IdleConnTimeout
|
||||
}
|
||||
|
||||
if t.t1 != nil {
|
||||
return t.t1.IdleConnTimeout
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
|
|
@ -3399,34 +3150,3 @@ func traceFirstResponseByte(trace *httptrace.ClientTrace) {
|
|||
trace.GotFirstResponseByte()
|
||||
}
|
||||
}
|
||||
|
||||
func traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool {
|
||||
return trace != nil && trace.WroteHeaderField != nil
|
||||
}
|
||||
|
||||
func traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) {
|
||||
if trace != nil && trace.WroteHeaderField != nil {
|
||||
trace.WroteHeaderField(k, []string{v})
|
||||
}
|
||||
}
|
||||
|
||||
func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error {
|
||||
if trace != nil {
|
||||
return trace.Got1xxResponse
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// dialTLSWithContext uses tls.Dialer, added in Go 1.15, to open a TLS
|
||||
// connection.
|
||||
func (t *Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) {
|
||||
dialer := &tls.Dialer{
|
||||
Config: cfg,
|
||||
}
|
||||
cn, err := dialer.DialContext(ctx, network, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsCn := cn.(*tls.Conn) // DialContext comment promises this will always succeed
|
||||
return tlsCn, nil
|
||||
}
|
||||
|
|
|
|||
3
vendor/golang.org/x/net/http2/writesched.go
generated
vendored
3
vendor/golang.org/x/net/http2/writesched.go
generated
vendored
|
|
@ -184,8 +184,7 @@ func (wr *FrameWriteRequest) replyToWriter(err error) {
|
|||
|
||||
// writeQueue is used by implementations of WriteScheduler.
|
||||
type writeQueue struct {
|
||||
s []FrameWriteRequest
|
||||
prev, next *writeQueue
|
||||
s []FrameWriteRequest
|
||||
}
|
||||
|
||||
func (q *writeQueue) empty() bool { return len(q.s) == 0 }
|
||||
|
|
|
|||
119
vendor/golang.org/x/net/http2/writesched_roundrobin.go
generated
vendored
119
vendor/golang.org/x/net/http2/writesched_roundrobin.go
generated
vendored
|
|
@ -1,119 +0,0 @@
|
|||
// Copyright 2023 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 http2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
type roundRobinWriteScheduler struct {
|
||||
// control contains control frames (SETTINGS, PING, etc.).
|
||||
control writeQueue
|
||||
|
||||
// streams maps stream ID to a queue.
|
||||
streams map[uint32]*writeQueue
|
||||
|
||||
// stream queues are stored in a circular linked list.
|
||||
// head is the next stream to write, or nil if there are no streams open.
|
||||
head *writeQueue
|
||||
|
||||
// pool of empty queues for reuse.
|
||||
queuePool writeQueuePool
|
||||
}
|
||||
|
||||
// newRoundRobinWriteScheduler constructs a new write scheduler.
|
||||
// The round robin scheduler priorizes control frames
|
||||
// like SETTINGS and PING over DATA frames.
|
||||
// When there are no control frames to send, it performs a round-robin
|
||||
// selection from the ready streams.
|
||||
func newRoundRobinWriteScheduler() WriteScheduler {
|
||||
ws := &roundRobinWriteScheduler{
|
||||
streams: make(map[uint32]*writeQueue),
|
||||
}
|
||||
return ws
|
||||
}
|
||||
|
||||
func (ws *roundRobinWriteScheduler) OpenStream(streamID uint32, options OpenStreamOptions) {
|
||||
if ws.streams[streamID] != nil {
|
||||
panic(fmt.Errorf("stream %d already opened", streamID))
|
||||
}
|
||||
q := ws.queuePool.get()
|
||||
ws.streams[streamID] = q
|
||||
if ws.head == nil {
|
||||
ws.head = q
|
||||
q.next = q
|
||||
q.prev = q
|
||||
} else {
|
||||
// Queues are stored in a ring.
|
||||
// Insert the new stream before ws.head, putting it at the end of the list.
|
||||
q.prev = ws.head.prev
|
||||
q.next = ws.head
|
||||
q.prev.next = q
|
||||
q.next.prev = q
|
||||
}
|
||||
}
|
||||
|
||||
func (ws *roundRobinWriteScheduler) CloseStream(streamID uint32) {
|
||||
q := ws.streams[streamID]
|
||||
if q == nil {
|
||||
return
|
||||
}
|
||||
if q.next == q {
|
||||
// This was the only open stream.
|
||||
ws.head = nil
|
||||
} else {
|
||||
q.prev.next = q.next
|
||||
q.next.prev = q.prev
|
||||
if ws.head == q {
|
||||
ws.head = q.next
|
||||
}
|
||||
}
|
||||
delete(ws.streams, streamID)
|
||||
ws.queuePool.put(q)
|
||||
}
|
||||
|
||||
func (ws *roundRobinWriteScheduler) AdjustStream(streamID uint32, priority PriorityParam) {}
|
||||
|
||||
func (ws *roundRobinWriteScheduler) Push(wr FrameWriteRequest) {
|
||||
if wr.isControl() {
|
||||
ws.control.push(wr)
|
||||
return
|
||||
}
|
||||
q := ws.streams[wr.StreamID()]
|
||||
if q == nil {
|
||||
// This is a closed stream.
|
||||
// wr should not be a HEADERS or DATA frame.
|
||||
// We push the request onto the control queue.
|
||||
if wr.DataSize() > 0 {
|
||||
panic("add DATA on non-open stream")
|
||||
}
|
||||
ws.control.push(wr)
|
||||
return
|
||||
}
|
||||
q.push(wr)
|
||||
}
|
||||
|
||||
func (ws *roundRobinWriteScheduler) Pop() (FrameWriteRequest, bool) {
|
||||
// Control and RST_STREAM frames first.
|
||||
if !ws.control.empty() {
|
||||
return ws.control.shift(), true
|
||||
}
|
||||
if ws.head == nil {
|
||||
return FrameWriteRequest{}, false
|
||||
}
|
||||
q := ws.head
|
||||
for {
|
||||
if wr, ok := q.consume(math.MaxInt32); ok {
|
||||
ws.head = q.next
|
||||
return wr, true
|
||||
}
|
||||
q = q.next
|
||||
if q == ws.head {
|
||||
break
|
||||
}
|
||||
}
|
||||
return FrameWriteRequest{}, false
|
||||
}
|
||||
1
vendor/golang.org/x/net/idna/go118.go
generated
vendored
1
vendor/golang.org/x/net/idna/go118.go
generated
vendored
|
|
@ -5,6 +5,7 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
package idna
|
||||
|
||||
|
|
|
|||
1
vendor/golang.org/x/net/idna/idna10.0.0.go
generated
vendored
1
vendor/golang.org/x/net/idna/idna10.0.0.go
generated
vendored
|
|
@ -5,6 +5,7 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.10
|
||||
// +build go1.10
|
||||
|
||||
// Package idna implements IDNA2008 using the compatibility processing
|
||||
// defined by UTS (Unicode Technical Standard) #46, which defines a standard to
|
||||
|
|
|
|||
3
vendor/golang.org/x/net/idna/idna9.0.0.go
generated
vendored
3
vendor/golang.org/x/net/idna/idna9.0.0.go
generated
vendored
|
|
@ -5,6 +5,7 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !go1.10
|
||||
// +build !go1.10
|
||||
|
||||
// Package idna implements IDNA2008 using the compatibility processing
|
||||
// defined by UTS (Unicode Technical Standard) #46, which defines a standard to
|
||||
|
|
@ -120,7 +121,7 @@ func CheckJoiners(enable bool) Option {
|
|||
}
|
||||
}
|
||||
|
||||
// StrictDomainName limits the set of permissible ASCII characters to those
|
||||
// StrictDomainName limits the set of permissable ASCII characters to those
|
||||
// allowed in domain names as defined in RFC 1034 (A-Z, a-z, 0-9 and the
|
||||
// hyphen). This is set by default for MapForLookup and ValidateForRegistration,
|
||||
// but is only useful if ValidateLabels is set.
|
||||
|
|
|
|||
1
vendor/golang.org/x/net/idna/pre_go118.go
generated
vendored
1
vendor/golang.org/x/net/idna/pre_go118.go
generated
vendored
|
|
@ -5,6 +5,7 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !go1.18
|
||||
// +build !go1.18
|
||||
|
||||
package idna
|
||||
|
||||
|
|
|
|||
1
vendor/golang.org/x/net/idna/tables10.0.0.go
generated
vendored
1
vendor/golang.org/x/net/idna/tables10.0.0.go
generated
vendored
|
|
@ -1,6 +1,7 @@
|
|||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
||||
|
||||
//go:build go1.10 && !go1.13
|
||||
// +build go1.10,!go1.13
|
||||
|
||||
package idna
|
||||
|
||||
|
|
|
|||
1
vendor/golang.org/x/net/idna/tables11.0.0.go
generated
vendored
1
vendor/golang.org/x/net/idna/tables11.0.0.go
generated
vendored
|
|
@ -1,6 +1,7 @@
|
|||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
||||
|
||||
//go:build go1.13 && !go1.14
|
||||
// +build go1.13,!go1.14
|
||||
|
||||
package idna
|
||||
|
||||
|
|
|
|||
1
vendor/golang.org/x/net/idna/tables12.0.0.go
generated
vendored
1
vendor/golang.org/x/net/idna/tables12.0.0.go
generated
vendored
|
|
@ -1,6 +1,7 @@
|
|||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
||||
|
||||
//go:build go1.14 && !go1.16
|
||||
// +build go1.14,!go1.16
|
||||
|
||||
package idna
|
||||
|
||||
|
|
|
|||
2987
vendor/golang.org/x/net/idna/tables13.0.0.go
generated
vendored
2987
vendor/golang.org/x/net/idna/tables13.0.0.go
generated
vendored
File diff suppressed because it is too large
Load diff
5144
vendor/golang.org/x/net/idna/tables15.0.0.go
generated
vendored
5144
vendor/golang.org/x/net/idna/tables15.0.0.go
generated
vendored
File diff suppressed because it is too large
Load diff
1
vendor/golang.org/x/net/idna/tables9.0.0.go
generated
vendored
1
vendor/golang.org/x/net/idna/tables9.0.0.go
generated
vendored
|
|
@ -1,6 +1,7 @@
|
|||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
||||
|
||||
//go:build !go1.10
|
||||
// +build !go1.10
|
||||
|
||||
package idna
|
||||
|
||||
|
|
|
|||
21
vendor/golang.org/x/net/idna/trie.go
generated
vendored
21
vendor/golang.org/x/net/idna/trie.go
generated
vendored
|
|
@ -6,6 +6,27 @@
|
|||
|
||||
package idna
|
||||
|
||||
// appendMapping appends the mapping for the respective rune. isMapped must be
|
||||
// true. A mapping is a categorization of a rune as defined in UTS #46.
|
||||
func (c info) appendMapping(b []byte, s string) []byte {
|
||||
index := int(c >> indexShift)
|
||||
if c&xorBit == 0 {
|
||||
s := mappings[index:]
|
||||
return append(b, s[1:s[0]+1]...)
|
||||
}
|
||||
b = append(b, s...)
|
||||
if c&inlineXOR == inlineXOR {
|
||||
// TODO: support and handle two-byte inline masks
|
||||
b[len(b)-1] ^= byte(index)
|
||||
} else {
|
||||
for p := len(b) - int(xorData[index]); p < len(b); p++ {
|
||||
index++
|
||||
b[p] ^= xorData[index]
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Sparse block handling code.
|
||||
|
||||
type valueRange struct {
|
||||
|
|
|
|||
30
vendor/golang.org/x/net/idna/trie12.0.0.go
generated
vendored
30
vendor/golang.org/x/net/idna/trie12.0.0.go
generated
vendored
|
|
@ -1,30 +0,0 @@
|
|||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
||||
|
||||
// Copyright 2016 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.
|
||||
|
||||
//go:build !go1.16
|
||||
|
||||
package idna
|
||||
|
||||
// appendMapping appends the mapping for the respective rune. isMapped must be
|
||||
// true. A mapping is a categorization of a rune as defined in UTS #46.
|
||||
func (c info) appendMapping(b []byte, s string) []byte {
|
||||
index := int(c >> indexShift)
|
||||
if c&xorBit == 0 {
|
||||
s := mappings[index:]
|
||||
return append(b, s[1:s[0]+1]...)
|
||||
}
|
||||
b = append(b, s...)
|
||||
if c&inlineXOR == inlineXOR {
|
||||
// TODO: support and handle two-byte inline masks
|
||||
b[len(b)-1] ^= byte(index)
|
||||
} else {
|
||||
for p := len(b) - int(xorData[index]); p < len(b); p++ {
|
||||
index++
|
||||
b[p] ^= xorData[index]
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
30
vendor/golang.org/x/net/idna/trie13.0.0.go
generated
vendored
30
vendor/golang.org/x/net/idna/trie13.0.0.go
generated
vendored
|
|
@ -1,30 +0,0 @@
|
|||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
||||
|
||||
// Copyright 2016 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.
|
||||
|
||||
//go:build go1.16
|
||||
|
||||
package idna
|
||||
|
||||
// appendMapping appends the mapping for the respective rune. isMapped must be
|
||||
// true. A mapping is a categorization of a rune as defined in UTS #46.
|
||||
func (c info) appendMapping(b []byte, s string) []byte {
|
||||
index := int(c >> indexShift)
|
||||
if c&xorBit == 0 {
|
||||
p := index
|
||||
return append(b, mappings[mappingIndex[p]:mappingIndex[p+1]]...)
|
||||
}
|
||||
b = append(b, s...)
|
||||
if c&inlineXOR == inlineXOR {
|
||||
// TODO: support and handle two-byte inline masks
|
||||
b[len(b)-1] ^= byte(index)
|
||||
} else {
|
||||
for p := len(b) - int(xorData[index]); p < len(b); p++ {
|
||||
index++
|
||||
b[p] ^= xorData[index]
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
4
vendor/golang.org/x/text/LICENSE
generated
vendored
4
vendor/golang.org/x/text/LICENSE
generated
vendored
|
|
@ -1,4 +1,4 @@
|
|||
Copyright 2009 The Go Authors.
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
|
|
@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
|
|||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google LLC nor the names of its
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
|
|
|
|||
4
vendor/golang.org/x/tools/go/ast/inspector/inspector.go
generated
vendored
4
vendor/golang.org/x/tools/go/ast/inspector/inspector.go
generated
vendored
|
|
@ -64,9 +64,8 @@ type event struct {
|
|||
// depth-first order. It calls f(n) for each node n before it visits
|
||||
// n's children.
|
||||
//
|
||||
// The complete traversal sequence is determined by ast.Inspect.
|
||||
// The types argument, if non-empty, enables type-based filtering of
|
||||
// events. The function f is called only for nodes whose type
|
||||
// events. The function f if is called only for nodes whose type
|
||||
// matches an element of the types slice.
|
||||
func (in *Inspector) Preorder(types []ast.Node, f func(ast.Node)) {
|
||||
// Because it avoids postorder calls to f, and the pruning
|
||||
|
|
@ -98,7 +97,6 @@ func (in *Inspector) Preorder(types []ast.Node, f func(ast.Node)) {
|
|||
// of the non-nil children of the node, followed by a call of
|
||||
// f(n, false).
|
||||
//
|
||||
// The complete traversal sequence is determined by ast.Inspect.
|
||||
// The types argument, if non-empty, enables type-based filtering of
|
||||
// events. The function f if is called only for nodes whose type
|
||||
// matches an element of the types slice.
|
||||
|
|
|
|||
4
vendor/golang.org/x/tools/go/ast/inspector/typeof.go
generated
vendored
4
vendor/golang.org/x/tools/go/ast/inspector/typeof.go
generated
vendored
|
|
@ -12,6 +12,8 @@ package inspector
|
|||
import (
|
||||
"go/ast"
|
||||
"math"
|
||||
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -169,7 +171,7 @@ func typeOf(n ast.Node) uint64 {
|
|||
return 1 << nIncDecStmt
|
||||
case *ast.IndexExpr:
|
||||
return 1 << nIndexExpr
|
||||
case *ast.IndexListExpr:
|
||||
case *typeparams.IndexListExpr:
|
||||
return 1 << nIndexListExpr
|
||||
case *ast.InterfaceType:
|
||||
return 1 << nInterfaceType
|
||||
|
|
|
|||
179
vendor/golang.org/x/tools/internal/typeparams/common.go
generated
vendored
Normal file
179
vendor/golang.org/x/tools/internal/typeparams/common.go
generated
vendored
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
// Copyright 2021 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 typeparams contains common utilities for writing tools that interact
|
||||
// with generic Go code, as introduced with Go 1.18.
|
||||
//
|
||||
// Many of the types and functions in this package are proxies for the new APIs
|
||||
// introduced in the standard library with Go 1.18. For example, the
|
||||
// typeparams.Union type is an alias for go/types.Union, and the ForTypeSpec
|
||||
// function returns the value of the go/ast.TypeSpec.TypeParams field. At Go
|
||||
// versions older than 1.18 these helpers are implemented as stubs, allowing
|
||||
// users of this package to write code that handles generic constructs inline,
|
||||
// even if the Go version being used to compile does not support generics.
|
||||
//
|
||||
// Additionally, this package contains common utilities for working with the
|
||||
// new generic constructs, to supplement the standard library APIs. Notably,
|
||||
// the StructuralTerms API computes a minimal representation of the structural
|
||||
// restrictions on a type parameter.
|
||||
//
|
||||
// An external version of these APIs is available in the
|
||||
// golang.org/x/exp/typeparams module.
|
||||
package typeparams
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
)
|
||||
|
||||
// UnpackIndexExpr extracts data from AST nodes that represent index
|
||||
// expressions.
|
||||
//
|
||||
// For an ast.IndexExpr, the resulting indices slice will contain exactly one
|
||||
// index expression. For an ast.IndexListExpr (go1.18+), it may have a variable
|
||||
// number of index expressions.
|
||||
//
|
||||
// For nodes that don't represent index expressions, the first return value of
|
||||
// UnpackIndexExpr will be nil.
|
||||
func UnpackIndexExpr(n ast.Node) (x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) {
|
||||
switch e := n.(type) {
|
||||
case *ast.IndexExpr:
|
||||
return e.X, e.Lbrack, []ast.Expr{e.Index}, e.Rbrack
|
||||
case *IndexListExpr:
|
||||
return e.X, e.Lbrack, e.Indices, e.Rbrack
|
||||
}
|
||||
return nil, token.NoPos, nil, token.NoPos
|
||||
}
|
||||
|
||||
// PackIndexExpr returns an *ast.IndexExpr or *ast.IndexListExpr, depending on
|
||||
// the cardinality of indices. Calling PackIndexExpr with len(indices) == 0
|
||||
// will panic.
|
||||
func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) ast.Expr {
|
||||
switch len(indices) {
|
||||
case 0:
|
||||
panic("empty indices")
|
||||
case 1:
|
||||
return &ast.IndexExpr{
|
||||
X: x,
|
||||
Lbrack: lbrack,
|
||||
Index: indices[0],
|
||||
Rbrack: rbrack,
|
||||
}
|
||||
default:
|
||||
return &IndexListExpr{
|
||||
X: x,
|
||||
Lbrack: lbrack,
|
||||
Indices: indices,
|
||||
Rbrack: rbrack,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IsTypeParam reports whether t is a type parameter.
|
||||
func IsTypeParam(t types.Type) bool {
|
||||
_, ok := t.(*TypeParam)
|
||||
return ok
|
||||
}
|
||||
|
||||
// OriginMethod returns the origin method associated with the method fn.
|
||||
// For methods on a non-generic receiver base type, this is just
|
||||
// fn. However, for methods with a generic receiver, OriginMethod returns the
|
||||
// corresponding method in the method set of the origin type.
|
||||
//
|
||||
// As a special case, if fn is not a method (has no receiver), OriginMethod
|
||||
// returns fn.
|
||||
func OriginMethod(fn *types.Func) *types.Func {
|
||||
recv := fn.Type().(*types.Signature).Recv()
|
||||
if recv == nil {
|
||||
|
||||
return fn
|
||||
}
|
||||
base := recv.Type()
|
||||
p, isPtr := base.(*types.Pointer)
|
||||
if isPtr {
|
||||
base = p.Elem()
|
||||
}
|
||||
named, isNamed := base.(*types.Named)
|
||||
if !isNamed {
|
||||
// Receiver is a *types.Interface.
|
||||
return fn
|
||||
}
|
||||
if ForNamed(named).Len() == 0 {
|
||||
// Receiver base has no type parameters, so we can avoid the lookup below.
|
||||
return fn
|
||||
}
|
||||
orig := NamedTypeOrigin(named)
|
||||
gfn, _, _ := types.LookupFieldOrMethod(orig, true, fn.Pkg(), fn.Name())
|
||||
return gfn.(*types.Func)
|
||||
}
|
||||
|
||||
// GenericAssignableTo is a generalization of types.AssignableTo that
|
||||
// implements the following rule for uninstantiated generic types:
|
||||
//
|
||||
// If V and T are generic named types, then V is considered assignable to T if,
|
||||
// for every possible instantation of V[A_1, ..., A_N], the instantiation
|
||||
// T[A_1, ..., A_N] is valid and V[A_1, ..., A_N] implements T[A_1, ..., A_N].
|
||||
//
|
||||
// If T has structural constraints, they must be satisfied by V.
|
||||
//
|
||||
// For example, consider the following type declarations:
|
||||
//
|
||||
// type Interface[T any] interface {
|
||||
// Accept(T)
|
||||
// }
|
||||
//
|
||||
// type Container[T any] struct {
|
||||
// Element T
|
||||
// }
|
||||
//
|
||||
// func (c Container[T]) Accept(t T) { c.Element = t }
|
||||
//
|
||||
// In this case, GenericAssignableTo reports that instantiations of Container
|
||||
// are assignable to the corresponding instantiation of Interface.
|
||||
func GenericAssignableTo(ctxt *Context, V, T types.Type) bool {
|
||||
// If V and T are not both named, or do not have matching non-empty type
|
||||
// parameter lists, fall back on types.AssignableTo.
|
||||
|
||||
VN, Vnamed := V.(*types.Named)
|
||||
TN, Tnamed := T.(*types.Named)
|
||||
if !Vnamed || !Tnamed {
|
||||
return types.AssignableTo(V, T)
|
||||
}
|
||||
|
||||
vtparams := ForNamed(VN)
|
||||
ttparams := ForNamed(TN)
|
||||
if vtparams.Len() == 0 || vtparams.Len() != ttparams.Len() || NamedTypeArgs(VN).Len() != 0 || NamedTypeArgs(TN).Len() != 0 {
|
||||
return types.AssignableTo(V, T)
|
||||
}
|
||||
|
||||
// V and T have the same (non-zero) number of type params. Instantiate both
|
||||
// with the type parameters of V. This must always succeed for V, and will
|
||||
// succeed for T if and only if the type set of each type parameter of V is a
|
||||
// subset of the type set of the corresponding type parameter of T, meaning
|
||||
// that every instantiation of V corresponds to a valid instantiation of T.
|
||||
|
||||
// Minor optimization: ensure we share a context across the two
|
||||
// instantiations below.
|
||||
if ctxt == nil {
|
||||
ctxt = NewContext()
|
||||
}
|
||||
|
||||
var targs []types.Type
|
||||
for i := 0; i < vtparams.Len(); i++ {
|
||||
targs = append(targs, vtparams.At(i))
|
||||
}
|
||||
|
||||
vinst, err := Instantiate(ctxt, V, targs, true)
|
||||
if err != nil {
|
||||
panic("type parameters should satisfy their own constraints")
|
||||
}
|
||||
|
||||
tinst, err := Instantiate(ctxt, T, targs, true)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return types.AssignableTo(vinst, tinst)
|
||||
}
|
||||
122
vendor/golang.org/x/tools/internal/typeparams/coretype.go
generated
vendored
Normal file
122
vendor/golang.org/x/tools/internal/typeparams/coretype.go
generated
vendored
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
// Copyright 2022 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 typeparams
|
||||
|
||||
import (
|
||||
"go/types"
|
||||
)
|
||||
|
||||
// CoreType returns the core type of T or nil if T does not have a core type.
|
||||
//
|
||||
// See https://go.dev/ref/spec#Core_types for the definition of a core type.
|
||||
func CoreType(T types.Type) types.Type {
|
||||
U := T.Underlying()
|
||||
if _, ok := U.(*types.Interface); !ok {
|
||||
return U // for non-interface types,
|
||||
}
|
||||
|
||||
terms, err := _NormalTerms(U)
|
||||
if len(terms) == 0 || err != nil {
|
||||
// len(terms) -> empty type set of interface.
|
||||
// err != nil => U is invalid, exceeds complexity bounds, or has an empty type set.
|
||||
return nil // no core type.
|
||||
}
|
||||
|
||||
U = terms[0].Type().Underlying()
|
||||
var identical int // i in [0,identical) => Identical(U, terms[i].Type().Underlying())
|
||||
for identical = 1; identical < len(terms); identical++ {
|
||||
if !types.Identical(U, terms[identical].Type().Underlying()) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if identical == len(terms) {
|
||||
// https://go.dev/ref/spec#Core_types
|
||||
// "There is a single type U which is the underlying type of all types in the type set of T"
|
||||
return U
|
||||
}
|
||||
ch, ok := U.(*types.Chan)
|
||||
if !ok {
|
||||
return nil // no core type as identical < len(terms) and U is not a channel.
|
||||
}
|
||||
// https://go.dev/ref/spec#Core_types
|
||||
// "the type chan E if T contains only bidirectional channels, or the type chan<- E or
|
||||
// <-chan E depending on the direction of the directional channels present."
|
||||
for chans := identical; chans < len(terms); chans++ {
|
||||
curr, ok := terms[chans].Type().Underlying().(*types.Chan)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if !types.Identical(ch.Elem(), curr.Elem()) {
|
||||
return nil // channel elements are not identical.
|
||||
}
|
||||
if ch.Dir() == types.SendRecv {
|
||||
// ch is bidirectional. We can safely always use curr's direction.
|
||||
ch = curr
|
||||
} else if curr.Dir() != types.SendRecv && ch.Dir() != curr.Dir() {
|
||||
// ch and curr are not bidirectional and not the same direction.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return ch
|
||||
}
|
||||
|
||||
// _NormalTerms returns a slice of terms representing the normalized structural
|
||||
// type restrictions of a type, if any.
|
||||
//
|
||||
// For all types other than *types.TypeParam, *types.Interface, and
|
||||
// *types.Union, this is just a single term with Tilde() == false and
|
||||
// Type() == typ. For *types.TypeParam, *types.Interface, and *types.Union, see
|
||||
// below.
|
||||
//
|
||||
// Structural type restrictions of a type parameter are created via
|
||||
// non-interface types embedded in its constraint interface (directly, or via a
|
||||
// chain of interface embeddings). For example, in the declaration type
|
||||
// T[P interface{~int; m()}] int the structural restriction of the type
|
||||
// parameter P is ~int.
|
||||
//
|
||||
// With interface embedding and unions, the specification of structural type
|
||||
// restrictions may be arbitrarily complex. For example, consider the
|
||||
// following:
|
||||
//
|
||||
// type A interface{ ~string|~[]byte }
|
||||
//
|
||||
// type B interface{ int|string }
|
||||
//
|
||||
// type C interface { ~string|~int }
|
||||
//
|
||||
// type T[P interface{ A|B; C }] int
|
||||
//
|
||||
// In this example, the structural type restriction of P is ~string|int: A|B
|
||||
// expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int,
|
||||
// which when intersected with C (~string|~int) yields ~string|int.
|
||||
//
|
||||
// _NormalTerms computes these expansions and reductions, producing a
|
||||
// "normalized" form of the embeddings. A structural restriction is normalized
|
||||
// if it is a single union containing no interface terms, and is minimal in the
|
||||
// sense that removing any term changes the set of types satisfying the
|
||||
// constraint. It is left as a proof for the reader that, modulo sorting, there
|
||||
// is exactly one such normalized form.
|
||||
//
|
||||
// Because the minimal representation always takes this form, _NormalTerms
|
||||
// returns a slice of tilde terms corresponding to the terms of the union in
|
||||
// the normalized structural restriction. An error is returned if the type is
|
||||
// invalid, exceeds complexity bounds, or has an empty type set. In the latter
|
||||
// case, _NormalTerms returns ErrEmptyTypeSet.
|
||||
//
|
||||
// _NormalTerms makes no guarantees about the order of terms, except that it
|
||||
// is deterministic.
|
||||
func _NormalTerms(typ types.Type) ([]*Term, error) {
|
||||
switch typ := typ.(type) {
|
||||
case *TypeParam:
|
||||
return StructuralTerms(typ)
|
||||
case *Union:
|
||||
return UnionTermSet(typ)
|
||||
case *types.Interface:
|
||||
return InterfaceTermSet(typ)
|
||||
default:
|
||||
return []*Term{NewTerm(false, typ)}, nil
|
||||
}
|
||||
}
|
||||
12
vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go
generated
vendored
Normal file
12
vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go
generated
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright 2021 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.
|
||||
|
||||
//go:build !go1.18
|
||||
// +build !go1.18
|
||||
|
||||
package typeparams
|
||||
|
||||
// Enabled reports whether type parameters are enabled in the current build
|
||||
// environment.
|
||||
const Enabled = false
|
||||
15
vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go
generated
vendored
Normal file
15
vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go
generated
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2021 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.
|
||||
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
package typeparams
|
||||
|
||||
// Note: this constant is in a separate file as this is the only acceptable
|
||||
// diff between the <1.18 API of this package and the 1.18 API.
|
||||
|
||||
// Enabled reports whether type parameters are enabled in the current build
|
||||
// environment.
|
||||
const Enabled = true
|
||||
218
vendor/golang.org/x/tools/internal/typeparams/normalize.go
generated
vendored
Normal file
218
vendor/golang.org/x/tools/internal/typeparams/normalize.go
generated
vendored
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
// Copyright 2021 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 typeparams
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/types"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//go:generate go run copytermlist.go
|
||||
|
||||
const debug = false
|
||||
|
||||
var ErrEmptyTypeSet = errors.New("empty type set")
|
||||
|
||||
// StructuralTerms returns a slice of terms representing the normalized
|
||||
// structural type restrictions of a type parameter, if any.
|
||||
//
|
||||
// Structural type restrictions of a type parameter are created via
|
||||
// non-interface types embedded in its constraint interface (directly, or via a
|
||||
// chain of interface embeddings). For example, in the declaration
|
||||
//
|
||||
// type T[P interface{~int; m()}] int
|
||||
//
|
||||
// the structural restriction of the type parameter P is ~int.
|
||||
//
|
||||
// With interface embedding and unions, the specification of structural type
|
||||
// restrictions may be arbitrarily complex. For example, consider the
|
||||
// following:
|
||||
//
|
||||
// type A interface{ ~string|~[]byte }
|
||||
//
|
||||
// type B interface{ int|string }
|
||||
//
|
||||
// type C interface { ~string|~int }
|
||||
//
|
||||
// type T[P interface{ A|B; C }] int
|
||||
//
|
||||
// In this example, the structural type restriction of P is ~string|int: A|B
|
||||
// expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int,
|
||||
// which when intersected with C (~string|~int) yields ~string|int.
|
||||
//
|
||||
// StructuralTerms computes these expansions and reductions, producing a
|
||||
// "normalized" form of the embeddings. A structural restriction is normalized
|
||||
// if it is a single union containing no interface terms, and is minimal in the
|
||||
// sense that removing any term changes the set of types satisfying the
|
||||
// constraint. It is left as a proof for the reader that, modulo sorting, there
|
||||
// is exactly one such normalized form.
|
||||
//
|
||||
// Because the minimal representation always takes this form, StructuralTerms
|
||||
// returns a slice of tilde terms corresponding to the terms of the union in
|
||||
// the normalized structural restriction. An error is returned if the
|
||||
// constraint interface is invalid, exceeds complexity bounds, or has an empty
|
||||
// type set. In the latter case, StructuralTerms returns ErrEmptyTypeSet.
|
||||
//
|
||||
// StructuralTerms makes no guarantees about the order of terms, except that it
|
||||
// is deterministic.
|
||||
func StructuralTerms(tparam *TypeParam) ([]*Term, error) {
|
||||
constraint := tparam.Constraint()
|
||||
if constraint == nil {
|
||||
return nil, fmt.Errorf("%s has nil constraint", tparam)
|
||||
}
|
||||
iface, _ := constraint.Underlying().(*types.Interface)
|
||||
if iface == nil {
|
||||
return nil, fmt.Errorf("constraint is %T, not *types.Interface", constraint.Underlying())
|
||||
}
|
||||
return InterfaceTermSet(iface)
|
||||
}
|
||||
|
||||
// InterfaceTermSet computes the normalized terms for a constraint interface,
|
||||
// returning an error if the term set cannot be computed or is empty. In the
|
||||
// latter case, the error will be ErrEmptyTypeSet.
|
||||
//
|
||||
// See the documentation of StructuralTerms for more information on
|
||||
// normalization.
|
||||
func InterfaceTermSet(iface *types.Interface) ([]*Term, error) {
|
||||
return computeTermSet(iface)
|
||||
}
|
||||
|
||||
// UnionTermSet computes the normalized terms for a union, returning an error
|
||||
// if the term set cannot be computed or is empty. In the latter case, the
|
||||
// error will be ErrEmptyTypeSet.
|
||||
//
|
||||
// See the documentation of StructuralTerms for more information on
|
||||
// normalization.
|
||||
func UnionTermSet(union *Union) ([]*Term, error) {
|
||||
return computeTermSet(union)
|
||||
}
|
||||
|
||||
func computeTermSet(typ types.Type) ([]*Term, error) {
|
||||
tset, err := computeTermSetInternal(typ, make(map[types.Type]*termSet), 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tset.terms.isEmpty() {
|
||||
return nil, ErrEmptyTypeSet
|
||||
}
|
||||
if tset.terms.isAll() {
|
||||
return nil, nil
|
||||
}
|
||||
var terms []*Term
|
||||
for _, term := range tset.terms {
|
||||
terms = append(terms, NewTerm(term.tilde, term.typ))
|
||||
}
|
||||
return terms, nil
|
||||
}
|
||||
|
||||
// A termSet holds the normalized set of terms for a given type.
|
||||
//
|
||||
// The name termSet is intentionally distinct from 'type set': a type set is
|
||||
// all types that implement a type (and includes method restrictions), whereas
|
||||
// a term set just represents the structural restrictions on a type.
|
||||
type termSet struct {
|
||||
complete bool
|
||||
terms termlist
|
||||
}
|
||||
|
||||
func indentf(depth int, format string, args ...interface{}) {
|
||||
fmt.Fprintf(os.Stderr, strings.Repeat(".", depth)+format+"\n", args...)
|
||||
}
|
||||
|
||||
func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth int) (res *termSet, err error) {
|
||||
if t == nil {
|
||||
panic("nil type")
|
||||
}
|
||||
|
||||
if debug {
|
||||
indentf(depth, "%s", t.String())
|
||||
defer func() {
|
||||
if err != nil {
|
||||
indentf(depth, "=> %s", err)
|
||||
} else {
|
||||
indentf(depth, "=> %s", res.terms.String())
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
const maxTermCount = 100
|
||||
if tset, ok := seen[t]; ok {
|
||||
if !tset.complete {
|
||||
return nil, fmt.Errorf("cycle detected in the declaration of %s", t)
|
||||
}
|
||||
return tset, nil
|
||||
}
|
||||
|
||||
// Mark the current type as seen to avoid infinite recursion.
|
||||
tset := new(termSet)
|
||||
defer func() {
|
||||
tset.complete = true
|
||||
}()
|
||||
seen[t] = tset
|
||||
|
||||
switch u := t.Underlying().(type) {
|
||||
case *types.Interface:
|
||||
// The term set of an interface is the intersection of the term sets of its
|
||||
// embedded types.
|
||||
tset.terms = allTermlist
|
||||
for i := 0; i < u.NumEmbeddeds(); i++ {
|
||||
embedded := u.EmbeddedType(i)
|
||||
if _, ok := embedded.Underlying().(*TypeParam); ok {
|
||||
return nil, fmt.Errorf("invalid embedded type %T", embedded)
|
||||
}
|
||||
tset2, err := computeTermSetInternal(embedded, seen, depth+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tset.terms = tset.terms.intersect(tset2.terms)
|
||||
}
|
||||
case *Union:
|
||||
// The term set of a union is the union of term sets of its terms.
|
||||
tset.terms = nil
|
||||
for i := 0; i < u.Len(); i++ {
|
||||
t := u.Term(i)
|
||||
var terms termlist
|
||||
switch t.Type().Underlying().(type) {
|
||||
case *types.Interface:
|
||||
tset2, err := computeTermSetInternal(t.Type(), seen, depth+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
terms = tset2.terms
|
||||
case *TypeParam, *Union:
|
||||
// A stand-alone type parameter or union is not permitted as union
|
||||
// term.
|
||||
return nil, fmt.Errorf("invalid union term %T", t)
|
||||
default:
|
||||
if t.Type() == types.Typ[types.Invalid] {
|
||||
continue
|
||||
}
|
||||
terms = termlist{{t.Tilde(), t.Type()}}
|
||||
}
|
||||
tset.terms = tset.terms.union(terms)
|
||||
if len(tset.terms) > maxTermCount {
|
||||
return nil, fmt.Errorf("exceeded max term count %d", maxTermCount)
|
||||
}
|
||||
}
|
||||
case *TypeParam:
|
||||
panic("unreachable")
|
||||
default:
|
||||
// For all other types, the term set is just a single non-tilde term
|
||||
// holding the type itself.
|
||||
if u != types.Typ[types.Invalid] {
|
||||
tset.terms = termlist{{false, t}}
|
||||
}
|
||||
}
|
||||
return tset, nil
|
||||
}
|
||||
|
||||
// under is a facade for the go/types internal function of the same name. It is
|
||||
// used by typeterm.go.
|
||||
func under(t types.Type) types.Type {
|
||||
return t.Underlying()
|
||||
}
|
||||
163
vendor/golang.org/x/tools/internal/typeparams/termlist.go
generated
vendored
Normal file
163
vendor/golang.org/x/tools/internal/typeparams/termlist.go
generated
vendored
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
// Copyright 2021 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.
|
||||
|
||||
// Code generated by copytermlist.go DO NOT EDIT.
|
||||
|
||||
package typeparams
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"go/types"
|
||||
)
|
||||
|
||||
// A termlist represents the type set represented by the union
|
||||
// t1 ∪ y2 ∪ ... tn of the type sets of the terms t1 to tn.
|
||||
// A termlist is in normal form if all terms are disjoint.
|
||||
// termlist operations don't require the operands to be in
|
||||
// normal form.
|
||||
type termlist []*term
|
||||
|
||||
// allTermlist represents the set of all types.
|
||||
// It is in normal form.
|
||||
var allTermlist = termlist{new(term)}
|
||||
|
||||
// String prints the termlist exactly (without normalization).
|
||||
func (xl termlist) String() string {
|
||||
if len(xl) == 0 {
|
||||
return "∅"
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
for i, x := range xl {
|
||||
if i > 0 {
|
||||
buf.WriteString(" ∪ ")
|
||||
}
|
||||
buf.WriteString(x.String())
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// isEmpty reports whether the termlist xl represents the empty set of types.
|
||||
func (xl termlist) isEmpty() bool {
|
||||
// If there's a non-nil term, the entire list is not empty.
|
||||
// If the termlist is in normal form, this requires at most
|
||||
// one iteration.
|
||||
for _, x := range xl {
|
||||
if x != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// isAll reports whether the termlist xl represents the set of all types.
|
||||
func (xl termlist) isAll() bool {
|
||||
// If there's a 𝓤 term, the entire list is 𝓤.
|
||||
// If the termlist is in normal form, this requires at most
|
||||
// one iteration.
|
||||
for _, x := range xl {
|
||||
if x != nil && x.typ == nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// norm returns the normal form of xl.
|
||||
func (xl termlist) norm() termlist {
|
||||
// Quadratic algorithm, but good enough for now.
|
||||
// TODO(gri) fix asymptotic performance
|
||||
used := make([]bool, len(xl))
|
||||
var rl termlist
|
||||
for i, xi := range xl {
|
||||
if xi == nil || used[i] {
|
||||
continue
|
||||
}
|
||||
for j := i + 1; j < len(xl); j++ {
|
||||
xj := xl[j]
|
||||
if xj == nil || used[j] {
|
||||
continue
|
||||
}
|
||||
if u1, u2 := xi.union(xj); u2 == nil {
|
||||
// If we encounter a 𝓤 term, the entire list is 𝓤.
|
||||
// Exit early.
|
||||
// (Note that this is not just an optimization;
|
||||
// if we continue, we may end up with a 𝓤 term
|
||||
// and other terms and the result would not be
|
||||
// in normal form.)
|
||||
if u1.typ == nil {
|
||||
return allTermlist
|
||||
}
|
||||
xi = u1
|
||||
used[j] = true // xj is now unioned into xi - ignore it in future iterations
|
||||
}
|
||||
}
|
||||
rl = append(rl, xi)
|
||||
}
|
||||
return rl
|
||||
}
|
||||
|
||||
// union returns the union xl ∪ yl.
|
||||
func (xl termlist) union(yl termlist) termlist {
|
||||
return append(xl, yl...).norm()
|
||||
}
|
||||
|
||||
// intersect returns the intersection xl ∩ yl.
|
||||
func (xl termlist) intersect(yl termlist) termlist {
|
||||
if xl.isEmpty() || yl.isEmpty() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Quadratic algorithm, but good enough for now.
|
||||
// TODO(gri) fix asymptotic performance
|
||||
var rl termlist
|
||||
for _, x := range xl {
|
||||
for _, y := range yl {
|
||||
if r := x.intersect(y); r != nil {
|
||||
rl = append(rl, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
return rl.norm()
|
||||
}
|
||||
|
||||
// equal reports whether xl and yl represent the same type set.
|
||||
func (xl termlist) equal(yl termlist) bool {
|
||||
// TODO(gri) this should be more efficient
|
||||
return xl.subsetOf(yl) && yl.subsetOf(xl)
|
||||
}
|
||||
|
||||
// includes reports whether t ∈ xl.
|
||||
func (xl termlist) includes(t types.Type) bool {
|
||||
for _, x := range xl {
|
||||
if x.includes(t) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// supersetOf reports whether y ⊆ xl.
|
||||
func (xl termlist) supersetOf(y *term) bool {
|
||||
for _, x := range xl {
|
||||
if y.subsetOf(x) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// subsetOf reports whether xl ⊆ yl.
|
||||
func (xl termlist) subsetOf(yl termlist) bool {
|
||||
if yl.isEmpty() {
|
||||
return xl.isEmpty()
|
||||
}
|
||||
|
||||
// each term x of xl must be a subset of yl
|
||||
for _, x := range xl {
|
||||
if !yl.supersetOf(x) {
|
||||
return false // x is not a subset yl
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
197
vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go
generated
vendored
Normal file
197
vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go
generated
vendored
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
// Copyright 2021 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.
|
||||
|
||||
//go:build !go1.18
|
||||
// +build !go1.18
|
||||
|
||||
package typeparams
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
)
|
||||
|
||||
func unsupported() {
|
||||
panic("type parameters are unsupported at this go version")
|
||||
}
|
||||
|
||||
// IndexListExpr is a placeholder type, as type parameters are not supported at
|
||||
// this Go version. Its methods panic on use.
|
||||
type IndexListExpr struct {
|
||||
ast.Expr
|
||||
X ast.Expr // expression
|
||||
Lbrack token.Pos // position of "["
|
||||
Indices []ast.Expr // index expressions
|
||||
Rbrack token.Pos // position of "]"
|
||||
}
|
||||
|
||||
// ForTypeSpec returns an empty field list, as type parameters on not supported
|
||||
// at this Go version.
|
||||
func ForTypeSpec(*ast.TypeSpec) *ast.FieldList {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ForFuncType returns an empty field list, as type parameters are not
|
||||
// supported at this Go version.
|
||||
func ForFuncType(*ast.FuncType) *ast.FieldList {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TypeParam is a placeholder type, as type parameters are not supported at
|
||||
// this Go version. Its methods panic on use.
|
||||
type TypeParam struct{ types.Type }
|
||||
|
||||
func (*TypeParam) Index() int { unsupported(); return 0 }
|
||||
func (*TypeParam) Constraint() types.Type { unsupported(); return nil }
|
||||
func (*TypeParam) Obj() *types.TypeName { unsupported(); return nil }
|
||||
|
||||
// TypeParamList is a placeholder for an empty type parameter list.
|
||||
type TypeParamList struct{}
|
||||
|
||||
func (*TypeParamList) Len() int { return 0 }
|
||||
func (*TypeParamList) At(int) *TypeParam { unsupported(); return nil }
|
||||
|
||||
// TypeList is a placeholder for an empty type list.
|
||||
type TypeList struct{}
|
||||
|
||||
func (*TypeList) Len() int { return 0 }
|
||||
func (*TypeList) At(int) types.Type { unsupported(); return nil }
|
||||
|
||||
// NewTypeParam is unsupported at this Go version, and panics.
|
||||
func NewTypeParam(name *types.TypeName, constraint types.Type) *TypeParam {
|
||||
unsupported()
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetTypeParamConstraint is unsupported at this Go version, and panics.
|
||||
func SetTypeParamConstraint(tparam *TypeParam, constraint types.Type) {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
// NewSignatureType calls types.NewSignature, panicking if recvTypeParams or
|
||||
// typeParams is non-empty.
|
||||
func NewSignatureType(recv *types.Var, recvTypeParams, typeParams []*TypeParam, params, results *types.Tuple, variadic bool) *types.Signature {
|
||||
if len(recvTypeParams) != 0 || len(typeParams) != 0 {
|
||||
panic("signatures cannot have type parameters at this Go version")
|
||||
}
|
||||
return types.NewSignature(recv, params, results, variadic)
|
||||
}
|
||||
|
||||
// ForSignature returns an empty slice.
|
||||
func ForSignature(*types.Signature) *TypeParamList {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RecvTypeParams returns a nil slice.
|
||||
func RecvTypeParams(sig *types.Signature) *TypeParamList {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsComparable returns false, as no interfaces are type-restricted at this Go
|
||||
// version.
|
||||
func IsComparable(*types.Interface) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsMethodSet returns true, as no interfaces are type-restricted at this Go
|
||||
// version.
|
||||
func IsMethodSet(*types.Interface) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsImplicit returns false, as no interfaces are implicit at this Go version.
|
||||
func IsImplicit(*types.Interface) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// MarkImplicit does nothing, because this Go version does not have implicit
|
||||
// interfaces.
|
||||
func MarkImplicit(*types.Interface) {}
|
||||
|
||||
// ForNamed returns an empty type parameter list, as type parameters are not
|
||||
// supported at this Go version.
|
||||
func ForNamed(*types.Named) *TypeParamList {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetForNamed panics if tparams is non-empty.
|
||||
func SetForNamed(_ *types.Named, tparams []*TypeParam) {
|
||||
if len(tparams) > 0 {
|
||||
unsupported()
|
||||
}
|
||||
}
|
||||
|
||||
// NamedTypeArgs returns nil.
|
||||
func NamedTypeArgs(*types.Named) *TypeList {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NamedTypeOrigin is the identity method at this Go version.
|
||||
func NamedTypeOrigin(named *types.Named) types.Type {
|
||||
return named
|
||||
}
|
||||
|
||||
// Term holds information about a structural type restriction.
|
||||
type Term struct {
|
||||
tilde bool
|
||||
typ types.Type
|
||||
}
|
||||
|
||||
func (m *Term) Tilde() bool { return m.tilde }
|
||||
func (m *Term) Type() types.Type { return m.typ }
|
||||
func (m *Term) String() string {
|
||||
pre := ""
|
||||
if m.tilde {
|
||||
pre = "~"
|
||||
}
|
||||
return pre + m.typ.String()
|
||||
}
|
||||
|
||||
// NewTerm is unsupported at this Go version, and panics.
|
||||
func NewTerm(tilde bool, typ types.Type) *Term {
|
||||
return &Term{tilde, typ}
|
||||
}
|
||||
|
||||
// Union is a placeholder type, as type parameters are not supported at this Go
|
||||
// version. Its methods panic on use.
|
||||
type Union struct{ types.Type }
|
||||
|
||||
func (*Union) Len() int { return 0 }
|
||||
func (*Union) Term(i int) *Term { unsupported(); return nil }
|
||||
|
||||
// NewUnion is unsupported at this Go version, and panics.
|
||||
func NewUnion(terms []*Term) *Union {
|
||||
unsupported()
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitInstanceInfo is a noop at this Go version.
|
||||
func InitInstanceInfo(*types.Info) {}
|
||||
|
||||
// Instance is a placeholder type, as type parameters are not supported at this
|
||||
// Go version.
|
||||
type Instance struct {
|
||||
TypeArgs *TypeList
|
||||
Type types.Type
|
||||
}
|
||||
|
||||
// GetInstances returns a nil map, as type parameters are not supported at this
|
||||
// Go version.
|
||||
func GetInstances(info *types.Info) map[*ast.Ident]Instance { return nil }
|
||||
|
||||
// Context is a placeholder type, as type parameters are not supported at
|
||||
// this Go version.
|
||||
type Context struct{}
|
||||
|
||||
// NewContext returns a placeholder Context instance.
|
||||
func NewContext() *Context {
|
||||
return &Context{}
|
||||
}
|
||||
|
||||
// Instantiate is unsupported on this Go version, and panics.
|
||||
func Instantiate(ctxt *Context, typ types.Type, targs []types.Type, validate bool) (types.Type, error) {
|
||||
unsupported()
|
||||
return nil, nil
|
||||
}
|
||||
151
vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go
generated
vendored
Normal file
151
vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go
generated
vendored
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
// Copyright 2021 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.
|
||||
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
package typeparams
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/types"
|
||||
)
|
||||
|
||||
// IndexListExpr is an alias for ast.IndexListExpr.
|
||||
type IndexListExpr = ast.IndexListExpr
|
||||
|
||||
// ForTypeSpec returns n.TypeParams.
|
||||
func ForTypeSpec(n *ast.TypeSpec) *ast.FieldList {
|
||||
if n == nil {
|
||||
return nil
|
||||
}
|
||||
return n.TypeParams
|
||||
}
|
||||
|
||||
// ForFuncType returns n.TypeParams.
|
||||
func ForFuncType(n *ast.FuncType) *ast.FieldList {
|
||||
if n == nil {
|
||||
return nil
|
||||
}
|
||||
return n.TypeParams
|
||||
}
|
||||
|
||||
// TypeParam is an alias for types.TypeParam
|
||||
type TypeParam = types.TypeParam
|
||||
|
||||
// TypeParamList is an alias for types.TypeParamList
|
||||
type TypeParamList = types.TypeParamList
|
||||
|
||||
// TypeList is an alias for types.TypeList
|
||||
type TypeList = types.TypeList
|
||||
|
||||
// NewTypeParam calls types.NewTypeParam.
|
||||
func NewTypeParam(name *types.TypeName, constraint types.Type) *TypeParam {
|
||||
return types.NewTypeParam(name, constraint)
|
||||
}
|
||||
|
||||
// SetTypeParamConstraint calls tparam.SetConstraint(constraint).
|
||||
func SetTypeParamConstraint(tparam *TypeParam, constraint types.Type) {
|
||||
tparam.SetConstraint(constraint)
|
||||
}
|
||||
|
||||
// NewSignatureType calls types.NewSignatureType.
|
||||
func NewSignatureType(recv *types.Var, recvTypeParams, typeParams []*TypeParam, params, results *types.Tuple, variadic bool) *types.Signature {
|
||||
return types.NewSignatureType(recv, recvTypeParams, typeParams, params, results, variadic)
|
||||
}
|
||||
|
||||
// ForSignature returns sig.TypeParams()
|
||||
func ForSignature(sig *types.Signature) *TypeParamList {
|
||||
return sig.TypeParams()
|
||||
}
|
||||
|
||||
// RecvTypeParams returns sig.RecvTypeParams().
|
||||
func RecvTypeParams(sig *types.Signature) *TypeParamList {
|
||||
return sig.RecvTypeParams()
|
||||
}
|
||||
|
||||
// IsComparable calls iface.IsComparable().
|
||||
func IsComparable(iface *types.Interface) bool {
|
||||
return iface.IsComparable()
|
||||
}
|
||||
|
||||
// IsMethodSet calls iface.IsMethodSet().
|
||||
func IsMethodSet(iface *types.Interface) bool {
|
||||
return iface.IsMethodSet()
|
||||
}
|
||||
|
||||
// IsImplicit calls iface.IsImplicit().
|
||||
func IsImplicit(iface *types.Interface) bool {
|
||||
return iface.IsImplicit()
|
||||
}
|
||||
|
||||
// MarkImplicit calls iface.MarkImplicit().
|
||||
func MarkImplicit(iface *types.Interface) {
|
||||
iface.MarkImplicit()
|
||||
}
|
||||
|
||||
// ForNamed extracts the (possibly empty) type parameter object list from
|
||||
// named.
|
||||
func ForNamed(named *types.Named) *TypeParamList {
|
||||
return named.TypeParams()
|
||||
}
|
||||
|
||||
// SetForNamed sets the type params tparams on n. Each tparam must be of
|
||||
// dynamic type *types.TypeParam.
|
||||
func SetForNamed(n *types.Named, tparams []*TypeParam) {
|
||||
n.SetTypeParams(tparams)
|
||||
}
|
||||
|
||||
// NamedTypeArgs returns named.TypeArgs().
|
||||
func NamedTypeArgs(named *types.Named) *TypeList {
|
||||
return named.TypeArgs()
|
||||
}
|
||||
|
||||
// NamedTypeOrigin returns named.Orig().
|
||||
func NamedTypeOrigin(named *types.Named) types.Type {
|
||||
return named.Origin()
|
||||
}
|
||||
|
||||
// Term is an alias for types.Term.
|
||||
type Term = types.Term
|
||||
|
||||
// NewTerm calls types.NewTerm.
|
||||
func NewTerm(tilde bool, typ types.Type) *Term {
|
||||
return types.NewTerm(tilde, typ)
|
||||
}
|
||||
|
||||
// Union is an alias for types.Union
|
||||
type Union = types.Union
|
||||
|
||||
// NewUnion calls types.NewUnion.
|
||||
func NewUnion(terms []*Term) *Union {
|
||||
return types.NewUnion(terms)
|
||||
}
|
||||
|
||||
// InitInstanceInfo initializes info to record information about type and
|
||||
// function instances.
|
||||
func InitInstanceInfo(info *types.Info) {
|
||||
info.Instances = make(map[*ast.Ident]types.Instance)
|
||||
}
|
||||
|
||||
// Instance is an alias for types.Instance.
|
||||
type Instance = types.Instance
|
||||
|
||||
// GetInstances returns info.Instances.
|
||||
func GetInstances(info *types.Info) map[*ast.Ident]Instance {
|
||||
return info.Instances
|
||||
}
|
||||
|
||||
// Context is an alias for types.Context.
|
||||
type Context = types.Context
|
||||
|
||||
// NewContext calls types.NewContext.
|
||||
func NewContext() *Context {
|
||||
return types.NewContext()
|
||||
}
|
||||
|
||||
// Instantiate calls types.Instantiate.
|
||||
func Instantiate(ctxt *Context, typ types.Type, targs []types.Type, validate bool) (types.Type, error) {
|
||||
return types.Instantiate(ctxt, typ, targs, validate)
|
||||
}
|
||||
170
vendor/golang.org/x/tools/internal/typeparams/typeterm.go
generated
vendored
Normal file
170
vendor/golang.org/x/tools/internal/typeparams/typeterm.go
generated
vendored
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
// Copyright 2021 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.
|
||||
|
||||
// Code generated by copytermlist.go DO NOT EDIT.
|
||||
|
||||
package typeparams
|
||||
|
||||
import "go/types"
|
||||
|
||||
// A term describes elementary type sets:
|
||||
//
|
||||
// ∅: (*term)(nil) == ∅ // set of no types (empty set)
|
||||
// 𝓤: &term{} == 𝓤 // set of all types (𝓤niverse)
|
||||
// T: &term{false, T} == {T} // set of type T
|
||||
// ~t: &term{true, t} == {t' | under(t') == t} // set of types with underlying type t
|
||||
//
|
||||
type term struct {
|
||||
tilde bool // valid if typ != nil
|
||||
typ types.Type
|
||||
}
|
||||
|
||||
func (x *term) String() string {
|
||||
switch {
|
||||
case x == nil:
|
||||
return "∅"
|
||||
case x.typ == nil:
|
||||
return "𝓤"
|
||||
case x.tilde:
|
||||
return "~" + x.typ.String()
|
||||
default:
|
||||
return x.typ.String()
|
||||
}
|
||||
}
|
||||
|
||||
// equal reports whether x and y represent the same type set.
|
||||
func (x *term) equal(y *term) bool {
|
||||
// easy cases
|
||||
switch {
|
||||
case x == nil || y == nil:
|
||||
return x == y
|
||||
case x.typ == nil || y.typ == nil:
|
||||
return x.typ == y.typ
|
||||
}
|
||||
// ∅ ⊂ x, y ⊂ 𝓤
|
||||
|
||||
return x.tilde == y.tilde && types.Identical(x.typ, y.typ)
|
||||
}
|
||||
|
||||
// union returns the union x ∪ y: zero, one, or two non-nil terms.
|
||||
func (x *term) union(y *term) (_, _ *term) {
|
||||
// easy cases
|
||||
switch {
|
||||
case x == nil && y == nil:
|
||||
return nil, nil // ∅ ∪ ∅ == ∅
|
||||
case x == nil:
|
||||
return y, nil // ∅ ∪ y == y
|
||||
case y == nil:
|
||||
return x, nil // x ∪ ∅ == x
|
||||
case x.typ == nil:
|
||||
return x, nil // 𝓤 ∪ y == 𝓤
|
||||
case y.typ == nil:
|
||||
return y, nil // x ∪ 𝓤 == 𝓤
|
||||
}
|
||||
// ∅ ⊂ x, y ⊂ 𝓤
|
||||
|
||||
if x.disjoint(y) {
|
||||
return x, y // x ∪ y == (x, y) if x ∩ y == ∅
|
||||
}
|
||||
// x.typ == y.typ
|
||||
|
||||
// ~t ∪ ~t == ~t
|
||||
// ~t ∪ T == ~t
|
||||
// T ∪ ~t == ~t
|
||||
// T ∪ T == T
|
||||
if x.tilde || !y.tilde {
|
||||
return x, nil
|
||||
}
|
||||
return y, nil
|
||||
}
|
||||
|
||||
// intersect returns the intersection x ∩ y.
|
||||
func (x *term) intersect(y *term) *term {
|
||||
// easy cases
|
||||
switch {
|
||||
case x == nil || y == nil:
|
||||
return nil // ∅ ∩ y == ∅ and ∩ ∅ == ∅
|
||||
case x.typ == nil:
|
||||
return y // 𝓤 ∩ y == y
|
||||
case y.typ == nil:
|
||||
return x // x ∩ 𝓤 == x
|
||||
}
|
||||
// ∅ ⊂ x, y ⊂ 𝓤
|
||||
|
||||
if x.disjoint(y) {
|
||||
return nil // x ∩ y == ∅ if x ∩ y == ∅
|
||||
}
|
||||
// x.typ == y.typ
|
||||
|
||||
// ~t ∩ ~t == ~t
|
||||
// ~t ∩ T == T
|
||||
// T ∩ ~t == T
|
||||
// T ∩ T == T
|
||||
if !x.tilde || y.tilde {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
// includes reports whether t ∈ x.
|
||||
func (x *term) includes(t types.Type) bool {
|
||||
// easy cases
|
||||
switch {
|
||||
case x == nil:
|
||||
return false // t ∈ ∅ == false
|
||||
case x.typ == nil:
|
||||
return true // t ∈ 𝓤 == true
|
||||
}
|
||||
// ∅ ⊂ x ⊂ 𝓤
|
||||
|
||||
u := t
|
||||
if x.tilde {
|
||||
u = under(u)
|
||||
}
|
||||
return types.Identical(x.typ, u)
|
||||
}
|
||||
|
||||
// subsetOf reports whether x ⊆ y.
|
||||
func (x *term) subsetOf(y *term) bool {
|
||||
// easy cases
|
||||
switch {
|
||||
case x == nil:
|
||||
return true // ∅ ⊆ y == true
|
||||
case y == nil:
|
||||
return false // x ⊆ ∅ == false since x != ∅
|
||||
case y.typ == nil:
|
||||
return true // x ⊆ 𝓤 == true
|
||||
case x.typ == nil:
|
||||
return false // 𝓤 ⊆ y == false since y != 𝓤
|
||||
}
|
||||
// ∅ ⊂ x, y ⊂ 𝓤
|
||||
|
||||
if x.disjoint(y) {
|
||||
return false // x ⊆ y == false if x ∩ y == ∅
|
||||
}
|
||||
// x.typ == y.typ
|
||||
|
||||
// ~t ⊆ ~t == true
|
||||
// ~t ⊆ T == false
|
||||
// T ⊆ ~t == true
|
||||
// T ⊆ T == true
|
||||
return !x.tilde || y.tilde
|
||||
}
|
||||
|
||||
// disjoint reports whether x ∩ y == ∅.
|
||||
// x.typ and y.typ must not be nil.
|
||||
func (x *term) disjoint(y *term) bool {
|
||||
if debug && (x.typ == nil || y.typ == nil) {
|
||||
panic("invalid argument(s)")
|
||||
}
|
||||
ux := x.typ
|
||||
if y.tilde {
|
||||
ux = under(ux)
|
||||
}
|
||||
uy := y.typ
|
||||
if x.tilde {
|
||||
uy = under(uy)
|
||||
}
|
||||
return !types.Identical(ux, uy)
|
||||
}
|
||||
11
vendor/modules.txt
vendored
11
vendor/modules.txt
vendored
|
|
@ -843,8 +843,8 @@ golang.org/x/crypto/ssh
|
|||
golang.org/x/crypto/ssh/agent
|
||||
golang.org/x/crypto/ssh/internal/bcrypt_pbkdf
|
||||
golang.org/x/crypto/ssh/knownhosts
|
||||
# golang.org/x/net v0.25.0
|
||||
## explicit; go 1.18
|
||||
# golang.org/x/net v0.6.0
|
||||
## explicit; go 1.17
|
||||
golang.org/x/net/context
|
||||
golang.org/x/net/html
|
||||
golang.org/x/net/html/atom
|
||||
|
|
@ -870,7 +870,7 @@ golang.org/x/sys/windows/registry
|
|||
# golang.org/x/term v0.29.0
|
||||
## explicit; go 1.18
|
||||
golang.org/x/term
|
||||
# golang.org/x/text v0.22.0
|
||||
# golang.org/x/text v0.15.0
|
||||
## explicit; go 1.18
|
||||
golang.org/x/text/encoding
|
||||
golang.org/x/text/encoding/charmap
|
||||
|
|
@ -892,9 +892,10 @@ golang.org/x/text/secure/bidirule
|
|||
golang.org/x/text/transform
|
||||
golang.org/x/text/unicode/bidi
|
||||
golang.org/x/text/unicode/norm
|
||||
# golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d
|
||||
## explicit; go 1.19
|
||||
# golang.org/x/tools v0.6.0
|
||||
## explicit; go 1.18
|
||||
golang.org/x/tools/go/ast/inspector
|
||||
golang.org/x/tools/internal/typeparams
|
||||
# google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f
|
||||
## explicit; go 1.15
|
||||
google.golang.org/genproto/googleapis/rpc/status
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue