Merge pull request #5996 from thaJeztah/bump_x_deps

vendor: update golang.org/x/.. dependencies
This commit is contained in:
Paweł Gronowski 2025-04-10 09:23:17 +00:00 committed by GitHub
commit e587e8a269
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 1140 additions and 536 deletions

View File

@ -52,10 +52,10 @@ require (
go.opentelemetry.io/otel/sdk v1.31.0 go.opentelemetry.io/otel/sdk v1.31.0
go.opentelemetry.io/otel/sdk/metric v1.31.0 go.opentelemetry.io/otel/sdk/metric v1.31.0
go.opentelemetry.io/otel/trace v1.31.0 go.opentelemetry.io/otel/trace v1.31.0
golang.org/x/sync v0.11.0 golang.org/x/sync v0.13.0
golang.org/x/sys v0.31.0 golang.org/x/sys v0.32.0
golang.org/x/term v0.29.0 golang.org/x/term v0.31.0
golang.org/x/text v0.22.0 golang.org/x/text v0.24.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
gotest.tools/v3 v3.5.2 gotest.tools/v3 v3.5.2
tags.cncf.io/container-device-interface v0.8.0 tags.cncf.io/container-device-interface v0.8.0
@ -98,9 +98,9 @@ require (
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect
golang.org/x/crypto v0.35.0 // indirect golang.org/x/crypto v0.37.0 // indirect
golang.org/x/net v0.33.0 // indirect golang.org/x/net v0.39.0 // indirect
golang.org/x/time v0.6.0 // indirect golang.org/x/time v0.11.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
google.golang.org/grpc v1.69.4 // indirect google.golang.org/grpc v1.69.4 // indirect

View File

@ -322,8 +322,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -333,16 +333,16 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -355,17 +355,17 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=

View File

@ -60,7 +60,7 @@ func configFromServer(h1 *http.Server, h2 *Server) http2Config {
return conf return conf
} }
// configFromServer merges configuration settings from h2 and h2.t1.HTTP2 // configFromTransport merges configuration settings from h2 and h2.t1.HTTP2
// (the net/http Transport). // (the net/http Transport).
func configFromTransport(h2 *Transport) http2Config { func configFromTransport(h2 *Transport) http2Config {
conf := http2Config{ conf := http2Config{

View File

@ -13,7 +13,7 @@ func fillNetHTTPServerConfig(conf *http2Config, srv *http.Server) {
fillNetHTTPConfig(conf, srv.HTTP2) fillNetHTTPConfig(conf, srv.HTTP2)
} }
// fillNetHTTPServerConfig sets fields in conf from tr.HTTP2. // fillNetHTTPTransportConfig sets fields in conf from tr.HTTP2.
func fillNetHTTPTransportConfig(conf *http2Config, tr *http.Transport) { func fillNetHTTPTransportConfig(conf *http2Config, tr *http.Transport) {
fillNetHTTPConfig(conf, tr.HTTP2) fillNetHTTPConfig(conf, tr.HTTP2)
} }

View File

@ -225,6 +225,11 @@ var fhBytes = sync.Pool{
}, },
} }
func invalidHTTP1LookingFrameHeader() FrameHeader {
fh, _ := readFrameHeader(make([]byte, frameHeaderLen), strings.NewReader("HTTP/1.1 "))
return fh
}
// ReadFrameHeader reads 9 bytes from r and returns a FrameHeader. // ReadFrameHeader reads 9 bytes from r and returns a FrameHeader.
// Most users should use Framer.ReadFrame instead. // Most users should use Framer.ReadFrame instead.
func ReadFrameHeader(r io.Reader) (FrameHeader, error) { func ReadFrameHeader(r io.Reader) (FrameHeader, error) {
@ -503,10 +508,16 @@ func (fr *Framer) ReadFrame() (Frame, error) {
return nil, err return nil, err
} }
if fh.Length > fr.maxReadSize { if fh.Length > fr.maxReadSize {
if fh == invalidHTTP1LookingFrameHeader() {
return nil, fmt.Errorf("http2: failed reading the frame payload: %w, note that the frame header looked like an HTTP/1.1 header", err)
}
return nil, ErrFrameTooLarge return nil, ErrFrameTooLarge
} }
payload := fr.getReadBuf(fh.Length) payload := fr.getReadBuf(fh.Length)
if _, err := io.ReadFull(fr.r, payload); err != nil { if _, err := io.ReadFull(fr.r, payload); err != nil {
if fh == invalidHTTP1LookingFrameHeader() {
return nil, fmt.Errorf("http2: failed reading the frame payload: %w, note that the frame header looked like an HTTP/1.1 header", err)
}
return nil, err return nil, err
} }
f, err := typeFrameParser(fh.Type)(fr.frameCache, fh, fr.countError, payload) f, err := typeFrameParser(fh.Type)(fr.frameCache, fh, fr.countError, payload)

View File

@ -34,11 +34,19 @@ import (
) )
var ( var (
VerboseLogs bool VerboseLogs bool
logFrameWrites bool logFrameWrites bool
logFrameReads bool logFrameReads bool
inTests bool inTests bool
disableExtendedConnectProtocol bool
// Enabling extended CONNECT by causes browsers to attempt to use
// WebSockets-over-HTTP/2. This results in problems when the server's websocket
// package doesn't support extended CONNECT.
//
// Disable extended CONNECT by default for now.
//
// Issue #71128.
disableExtendedConnectProtocol = true
) )
func init() { func init() {
@ -51,8 +59,8 @@ func init() {
logFrameWrites = true logFrameWrites = true
logFrameReads = true logFrameReads = true
} }
if strings.Contains(e, "http2xconnect=0") { if strings.Contains(e, "http2xconnect=1") {
disableExtendedConnectProtocol = true disableExtendedConnectProtocol = false
} }
} }
@ -407,23 +415,6 @@ func (s *sorter) SortStrings(ss []string) {
s.v = save s.v = save
} }
// validPseudoPath reports whether v is a valid :path pseudo-header
// value. It must be either:
//
// - a non-empty string starting with '/'
// - the string '*', for OPTIONS requests.
//
// For now this is only used a quick check for deciding when to clean
// up Opaque URLs before sending requests from the Transport.
// See golang.org/issue/16847
//
// We used to enforce that the path also didn't start with "//", but
// Google's GFE accepts such paths and Chrome sends them, so ignore
// that part of the spec. See golang.org/issue/19103.
func validPseudoPath(v string) bool {
return (len(v) > 0 && v[0] == '/') || v == "*"
}
// incomparable is a zero-width, non-comparable type. Adding it to a struct // incomparable is a zero-width, non-comparable type. Adding it to a struct
// makes that struct also non-comparable, and generally doesn't add // makes that struct also non-comparable, and generally doesn't add
// any size (as long as it's first). // any size (as long as it's first).

View File

@ -50,6 +50,7 @@ import (
"golang.org/x/net/http/httpguts" "golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack" "golang.org/x/net/http2/hpack"
"golang.org/x/net/internal/httpcommon"
) )
const ( const (
@ -812,8 +813,7 @@ const maxCachedCanonicalHeadersKeysSize = 2048
func (sc *serverConn) canonicalHeader(v string) string { func (sc *serverConn) canonicalHeader(v string) string {
sc.serveG.check() sc.serveG.check()
buildCommonHeaderMapsOnce() cv, ok := httpcommon.CachedCanonicalHeader(v)
cv, ok := commonCanonHeader[v]
if ok { if ok {
return cv return cv
} }
@ -1068,7 +1068,10 @@ func (sc *serverConn) serve(conf http2Config) {
func (sc *serverConn) handlePingTimer(lastFrameReadTime time.Time) { func (sc *serverConn) handlePingTimer(lastFrameReadTime time.Time) {
if sc.pingSent { if sc.pingSent {
sc.vlogf("timeout waiting for PING response") sc.logf("timeout waiting for PING response")
if f := sc.countErrorFunc; f != nil {
f("conn_close_lost_ping")
}
sc.conn.Close() sc.conn.Close()
return return
} }
@ -2233,25 +2236,25 @@ func (sc *serverConn) newStream(id, pusherID uint32, state streamState) *stream
func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*responseWriter, *http.Request, error) { func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*responseWriter, *http.Request, error) {
sc.serveG.check() sc.serveG.check()
rp := requestParam{ rp := httpcommon.ServerRequestParam{
method: f.PseudoValue("method"), Method: f.PseudoValue("method"),
scheme: f.PseudoValue("scheme"), Scheme: f.PseudoValue("scheme"),
authority: f.PseudoValue("authority"), Authority: f.PseudoValue("authority"),
path: f.PseudoValue("path"), Path: f.PseudoValue("path"),
protocol: f.PseudoValue("protocol"), Protocol: f.PseudoValue("protocol"),
} }
// extended connect is disabled, so we should not see :protocol // extended connect is disabled, so we should not see :protocol
if disableExtendedConnectProtocol && rp.protocol != "" { if disableExtendedConnectProtocol && rp.Protocol != "" {
return nil, nil, sc.countError("bad_connect", streamError(f.StreamID, ErrCodeProtocol)) return nil, nil, sc.countError("bad_connect", streamError(f.StreamID, ErrCodeProtocol))
} }
isConnect := rp.method == "CONNECT" isConnect := rp.Method == "CONNECT"
if isConnect { if isConnect {
if rp.protocol == "" && (rp.path != "" || rp.scheme != "" || rp.authority == "") { if rp.Protocol == "" && (rp.Path != "" || rp.Scheme != "" || rp.Authority == "") {
return nil, nil, sc.countError("bad_connect", streamError(f.StreamID, ErrCodeProtocol)) return nil, nil, sc.countError("bad_connect", streamError(f.StreamID, ErrCodeProtocol))
} }
} else if rp.method == "" || rp.path == "" || (rp.scheme != "https" && rp.scheme != "http") { } else if rp.Method == "" || rp.Path == "" || (rp.Scheme != "https" && rp.Scheme != "http") {
// See 8.1.2.6 Malformed Requests and Responses: // See 8.1.2.6 Malformed Requests and Responses:
// //
// Malformed requests or responses that are detected // Malformed requests or responses that are detected
@ -2265,15 +2268,16 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res
return nil, nil, sc.countError("bad_path_method", streamError(f.StreamID, ErrCodeProtocol)) return nil, nil, sc.countError("bad_path_method", streamError(f.StreamID, ErrCodeProtocol))
} }
rp.header = make(http.Header) header := make(http.Header)
rp.Header = header
for _, hf := range f.RegularFields() { for _, hf := range f.RegularFields() {
rp.header.Add(sc.canonicalHeader(hf.Name), hf.Value) header.Add(sc.canonicalHeader(hf.Name), hf.Value)
} }
if rp.authority == "" { if rp.Authority == "" {
rp.authority = rp.header.Get("Host") rp.Authority = header.Get("Host")
} }
if rp.protocol != "" { if rp.Protocol != "" {
rp.header.Set(":protocol", rp.protocol) header.Set(":protocol", rp.Protocol)
} }
rw, req, err := sc.newWriterAndRequestNoBody(st, rp) rw, req, err := sc.newWriterAndRequestNoBody(st, rp)
@ -2282,7 +2286,7 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res
} }
bodyOpen := !f.StreamEnded() bodyOpen := !f.StreamEnded()
if bodyOpen { if bodyOpen {
if vv, ok := rp.header["Content-Length"]; ok { if vv, ok := rp.Header["Content-Length"]; ok {
if cl, err := strconv.ParseUint(vv[0], 10, 63); err == nil { if cl, err := strconv.ParseUint(vv[0], 10, 63); err == nil {
req.ContentLength = int64(cl) req.ContentLength = int64(cl)
} else { } else {
@ -2298,84 +2302,38 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res
return rw, req, nil return rw, req, nil
} }
type requestParam struct { func (sc *serverConn) newWriterAndRequestNoBody(st *stream, rp httpcommon.ServerRequestParam) (*responseWriter, *http.Request, error) {
method string
scheme, authority, path string
protocol string
header http.Header
}
func (sc *serverConn) newWriterAndRequestNoBody(st *stream, rp requestParam) (*responseWriter, *http.Request, error) {
sc.serveG.check() sc.serveG.check()
var tlsState *tls.ConnectionState // nil if not scheme https var tlsState *tls.ConnectionState // nil if not scheme https
if rp.scheme == "https" { if rp.Scheme == "https" {
tlsState = sc.tlsState tlsState = sc.tlsState
} }
needsContinue := httpguts.HeaderValuesContainsToken(rp.header["Expect"], "100-continue") res := httpcommon.NewServerRequest(rp)
if needsContinue { if res.InvalidReason != "" {
rp.header.Del("Expect") return nil, nil, sc.countError(res.InvalidReason, streamError(st.id, ErrCodeProtocol))
}
// Merge Cookie headers into one "; "-delimited value.
if cookies := rp.header["Cookie"]; len(cookies) > 1 {
rp.header.Set("Cookie", strings.Join(cookies, "; "))
}
// Setup Trailers
var trailer http.Header
for _, v := range rp.header["Trailer"] {
for _, key := range strings.Split(v, ",") {
key = http.CanonicalHeaderKey(textproto.TrimString(key))
switch key {
case "Transfer-Encoding", "Trailer", "Content-Length":
// Bogus. (copy of http1 rules)
// Ignore.
default:
if trailer == nil {
trailer = make(http.Header)
}
trailer[key] = nil
}
}
}
delete(rp.header, "Trailer")
var url_ *url.URL
var requestURI string
if rp.method == "CONNECT" && rp.protocol == "" {
url_ = &url.URL{Host: rp.authority}
requestURI = rp.authority // mimic HTTP/1 server behavior
} else {
var err error
url_, err = url.ParseRequestURI(rp.path)
if err != nil {
return nil, nil, sc.countError("bad_path", streamError(st.id, ErrCodeProtocol))
}
requestURI = rp.path
} }
body := &requestBody{ body := &requestBody{
conn: sc, conn: sc,
stream: st, stream: st,
needsContinue: needsContinue, needsContinue: res.NeedsContinue,
} }
req := &http.Request{ req := (&http.Request{
Method: rp.method, Method: rp.Method,
URL: url_, URL: res.URL,
RemoteAddr: sc.remoteAddrStr, RemoteAddr: sc.remoteAddrStr,
Header: rp.header, Header: rp.Header,
RequestURI: requestURI, RequestURI: res.RequestURI,
Proto: "HTTP/2.0", Proto: "HTTP/2.0",
ProtoMajor: 2, ProtoMajor: 2,
ProtoMinor: 0, ProtoMinor: 0,
TLS: tlsState, TLS: tlsState,
Host: rp.authority, Host: rp.Authority,
Body: body, Body: body,
Trailer: trailer, Trailer: res.Trailer,
} }).WithContext(st.ctx)
req = req.WithContext(st.ctx)
rw := sc.newResponseWriter(st, req) rw := sc.newResponseWriter(st, req)
return rw, req, nil return rw, req, nil
} }
@ -3270,12 +3228,12 @@ func (sc *serverConn) startPush(msg *startPushRequest) {
// we start in "half closed (remote)" for simplicity. // we start in "half closed (remote)" for simplicity.
// See further comments at the definition of stateHalfClosedRemote. // See further comments at the definition of stateHalfClosedRemote.
promised := sc.newStream(promisedID, msg.parent.id, stateHalfClosedRemote) promised := sc.newStream(promisedID, msg.parent.id, stateHalfClosedRemote)
rw, req, err := sc.newWriterAndRequestNoBody(promised, requestParam{ rw, req, err := sc.newWriterAndRequestNoBody(promised, httpcommon.ServerRequestParam{
method: msg.method, Method: msg.method,
scheme: msg.url.Scheme, Scheme: msg.url.Scheme,
authority: msg.url.Host, Authority: msg.url.Host,
path: msg.url.RequestURI(), Path: msg.url.RequestURI(),
header: cloneHeader(msg.header), // clone since handler runs concurrently with writing the PUSH_PROMISE Header: cloneHeader(msg.header), // clone since handler runs concurrently with writing the PUSH_PROMISE
}) })
if err != nil { if err != nil {
// Should not happen, since we've already validated msg.url. // Should not happen, since we've already validated msg.url.

View File

@ -25,7 +25,6 @@ import (
"net/http" "net/http"
"net/http/httptrace" "net/http/httptrace"
"net/textproto" "net/textproto"
"sort"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
@ -35,6 +34,7 @@ import (
"golang.org/x/net/http/httpguts" "golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack" "golang.org/x/net/http2/hpack"
"golang.org/x/net/idna" "golang.org/x/net/idna"
"golang.org/x/net/internal/httpcommon"
) )
const ( const (
@ -375,6 +375,7 @@ type ClientConn struct {
doNotReuse bool // whether conn is marked to not be reused for any future requests doNotReuse bool // whether conn is marked to not be reused for any future requests
closing bool closing bool
closed bool closed bool
closedOnIdle bool // true if conn was closed for idleness
seenSettings bool // true if we've seen a settings frame, false otherwise seenSettings bool // true if we've seen a settings frame, false otherwise
seenSettingsChan chan struct{} // closed when seenSettings is true or frame reading fails seenSettingsChan chan struct{} // closed when seenSettings is true or frame reading fails
wantSettingsAck bool // we sent a SETTINGS frame and haven't heard back wantSettingsAck bool // we sent a SETTINGS frame and haven't heard back
@ -1089,10 +1090,12 @@ func (cc *ClientConn) idleStateLocked() (st clientConnIdleState) {
// If this connection has never been used for a request and is closed, // If this connection has never been used for a request and is closed,
// then let it take a request (which will fail). // then let it take a request (which will fail).
// If the conn was closed for idleness, we're racing the idle timer;
// don't try to use the conn. (Issue #70515.)
// //
// This avoids a situation where an error early in a connection's lifetime // This avoids a situation where an error early in a connection's lifetime
// goes unreported. // goes unreported.
if cc.nextStreamID == 1 && cc.streamsReserved == 0 && cc.closed { if cc.nextStreamID == 1 && cc.streamsReserved == 0 && cc.closed && !cc.closedOnIdle {
st.canTakeNewRequest = true st.canTakeNewRequest = true
} }
@ -1155,6 +1158,7 @@ func (cc *ClientConn) closeIfIdle() {
return return
} }
cc.closed = true cc.closed = true
cc.closedOnIdle = true
nextID := cc.nextStreamID nextID := cc.nextStreamID
// TODO: do clients send GOAWAY too? maybe? Just Close: // TODO: do clients send GOAWAY too? maybe? Just Close:
cc.mu.Unlock() cc.mu.Unlock()
@ -1271,23 +1275,6 @@ func (cc *ClientConn) closeForLostPing() {
// exported. At least they'll be DeepEqual for h1-vs-h2 comparisons tests. // exported. At least they'll be DeepEqual for h1-vs-h2 comparisons tests.
var errRequestCanceled = errors.New("net/http: request canceled") var errRequestCanceled = errors.New("net/http: request canceled")
func commaSeparatedTrailers(req *http.Request) (string, error) {
keys := make([]string, 0, len(req.Trailer))
for k := range req.Trailer {
k = canonicalHeader(k)
switch k {
case "Transfer-Encoding", "Trailer", "Content-Length":
return "", fmt.Errorf("invalid Trailer key %q", k)
}
keys = append(keys, k)
}
if len(keys) > 0 {
sort.Strings(keys)
return strings.Join(keys, ","), nil
}
return "", nil
}
func (cc *ClientConn) responseHeaderTimeout() time.Duration { func (cc *ClientConn) responseHeaderTimeout() time.Duration {
if cc.t.t1 != nil { if cc.t.t1 != nil {
return cc.t.t1.ResponseHeaderTimeout return cc.t.t1.ResponseHeaderTimeout
@ -1299,22 +1286,6 @@ func (cc *ClientConn) responseHeaderTimeout() time.Duration {
return 0 return 0
} }
// checkConnHeaders checks whether req has any invalid connection-level headers.
// per RFC 7540 section 8.1.2.2: Connection-Specific Header Fields.
// Certain headers are special-cased as okay but not transmitted later.
func checkConnHeaders(req *http.Request) error {
if v := req.Header.Get("Upgrade"); v != "" {
return fmt.Errorf("http2: invalid Upgrade request header: %q", req.Header["Upgrade"])
}
if vv := req.Header["Transfer-Encoding"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && vv[0] != "chunked") {
return fmt.Errorf("http2: invalid Transfer-Encoding request header: %q", vv)
}
if vv := req.Header["Connection"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && !asciiEqualFold(vv[0], "close") && !asciiEqualFold(vv[0], "keep-alive")) {
return fmt.Errorf("http2: invalid Connection request header: %q", vv)
}
return nil
}
// actualContentLength returns a sanitized version of // actualContentLength returns a sanitized version of
// req.ContentLength, where 0 actually means zero (not unknown) and -1 // req.ContentLength, where 0 actually means zero (not unknown) and -1
// means unknown. // means unknown.
@ -1360,25 +1331,7 @@ func (cc *ClientConn) roundTrip(req *http.Request, streamf func(*clientStream))
donec: make(chan struct{}), donec: make(chan struct{}),
} }
// TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere? cs.requestedGzip = httpcommon.IsRequestGzip(req.Method, req.Header, cc.t.disableCompression())
if !cc.t.disableCompression() &&
req.Header.Get("Accept-Encoding") == "" &&
req.Header.Get("Range") == "" &&
!cs.isHead {
// Request gzip only, not deflate. Deflate is ambiguous and
// not as universally supported anyway.
// See: https://zlib.net/zlib_faq.html#faq39
//
// Note that we don't request this for HEAD requests,
// due to a bug in nginx:
// http://trac.nginx.org/nginx/ticket/358
// https://golang.org/issue/5522
//
// We don't request gzip if the request is for a range, since
// auto-decoding a portion of a gzipped document will just fail
// anyway. See https://golang.org/issue/8923
cs.requestedGzip = true
}
go cs.doRequest(req, streamf) go cs.doRequest(req, streamf)
@ -1492,10 +1445,6 @@ func (cs *clientStream) writeRequest(req *http.Request, streamf func(*clientStre
cc := cs.cc cc := cs.cc
ctx := cs.ctx ctx := cs.ctx
if err := checkConnHeaders(req); err != nil {
return err
}
// wait for setting frames to be received, a server can change this value later, // wait for setting frames to be received, a server can change this value later,
// but we just wait for the first settings frame // but we just wait for the first settings frame
var isExtendedConnect bool var isExtendedConnect bool
@ -1659,26 +1608,39 @@ func (cs *clientStream) encodeAndWriteHeaders(req *http.Request) error {
// we send: HEADERS{1}, CONTINUATION{0,} + DATA{0,} (DATA is // we send: HEADERS{1}, CONTINUATION{0,} + DATA{0,} (DATA is
// sent by writeRequestBody below, along with any Trailers, // sent by writeRequestBody below, along with any Trailers,
// again in form HEADERS{1}, CONTINUATION{0,}) // again in form HEADERS{1}, CONTINUATION{0,})
trailers, err := commaSeparatedTrailers(req) cc.hbuf.Reset()
res, err := encodeRequestHeaders(req, cs.requestedGzip, cc.peerMaxHeaderListSize, func(name, value string) {
cc.writeHeader(name, value)
})
if err != nil { if err != nil {
return err return fmt.Errorf("http2: %w", err)
}
hasTrailers := trailers != ""
contentLen := actualContentLength(req)
hasBody := contentLen != 0
hdrs, err := cc.encodeHeaders(req, cs.requestedGzip, trailers, contentLen)
if err != nil {
return err
} }
hdrs := cc.hbuf.Bytes()
// Write the request. // Write the request.
endStream := !hasBody && !hasTrailers endStream := !res.HasBody && !res.HasTrailers
cs.sentHeaders = true cs.sentHeaders = true
err = cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs) err = cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs)
traceWroteHeaders(cs.trace) traceWroteHeaders(cs.trace)
return err return err
} }
func encodeRequestHeaders(req *http.Request, addGzipHeader bool, peerMaxHeaderListSize uint64, headerf func(name, value string)) (httpcommon.EncodeHeadersResult, error) {
return httpcommon.EncodeHeaders(req.Context(), httpcommon.EncodeHeadersParam{
Request: httpcommon.Request{
Header: req.Header,
Trailer: req.Trailer,
URL: req.URL,
Host: req.Host,
Method: req.Method,
ActualContentLength: actualContentLength(req),
},
AddGzipHeader: addGzipHeader,
PeerMaxHeaderListSize: peerMaxHeaderListSize,
DefaultUserAgent: defaultUserAgent,
}, headerf)
}
// cleanupWriteRequest performs post-request tasks. // cleanupWriteRequest performs post-request tasks.
// //
// If err (the result of writeRequest) is non-nil and the stream is not closed, // If err (the result of writeRequest) is non-nil and the stream is not closed,
@ -2066,218 +2028,6 @@ func (cs *clientStream) awaitFlowControl(maxBytes int) (taken int32, err error)
} }
} }
func validateHeaders(hdrs http.Header) string {
for k, vv := range hdrs {
if !httpguts.ValidHeaderFieldName(k) && k != ":protocol" {
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")
func isNormalConnect(req *http.Request) bool {
return req.Method == "CONNECT" && req.Header.Get(":protocol") == ""
}
// requires cc.wmu be held.
func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trailers string, contentLength int64) ([]byte, error) {
cc.hbuf.Reset()
if req.URL == nil {
return nil, errNilRequestURL
}
host := req.Host
if host == "" {
host = req.URL.Host
}
host, err := httpguts.PunycodeHostPort(host)
if err != nil {
return nil, err
}
if !httpguts.ValidHostHeader(host) {
return nil, errors.New("http2: invalid Host header")
}
var path string
if !isNormalConnect(req) {
path = req.URL.RequestURI()
if !validPseudoPath(path) {
orig := path
path = strings.TrimPrefix(path, req.URL.Scheme+"://"+host)
if !validPseudoPath(path) {
if req.URL.Opaque != "" {
return nil, fmt.Errorf("invalid request :path %q from URL.Opaque = %q", orig, req.URL.Opaque)
} else {
return nil, fmt.Errorf("invalid request :path %q", orig)
}
}
}
}
// Check for any invalid headers+trailers 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)
}
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
// [RFC3986]).
f(":authority", host)
m := req.Method
if m == "" {
m = http.MethodGet
}
f(":method", m)
if !isNormalConnect(req) {
f(":path", path)
f(":scheme", req.URL.Scheme)
}
if trailers != "" {
f("trailer", trailers)
}
var didUA bool
for k, vv := range req.Header {
if asciiEqualFold(k, "host") || asciiEqualFold(k, "content-length") {
// Host is :authority, already sent.
// Content-Length is automatic, set below.
continue
} else if asciiEqualFold(k, "connection") ||
asciiEqualFold(k, "proxy-connection") ||
asciiEqualFold(k, "transfer-encoding") ||
asciiEqualFold(k, "upgrade") ||
asciiEqualFold(k, "keep-alive") {
// Per 8.1.2.2 Connection-Specific Header
// Fields, don't send connection-specific
// fields. We have already checked if any
// are error-worthy so just ignore the rest.
continue
} else if asciiEqualFold(k, "user-agent") {
// Match Go's http1 behavior: at most one
// User-Agent. If set to nil or empty string,
// then omit it. Otherwise if not mentioned,
// include the default (below).
didUA = true
if len(vv) < 1 {
continue
}
vv = vv[:1]
if vv[0] == "" {
continue
}
} else if asciiEqualFold(k, "cookie") {
// Per 8.1.2.5 To allow for better compression efficiency, the
// Cookie header field MAY be split into separate header fields,
// each with one or more cookie-pairs.
for _, v := range vv {
for {
p := strings.IndexByte(v, ';')
if p < 0 {
break
}
f("cookie", v[:p])
p++
// strip space after semicolon if any.
for p+1 <= len(v) && v[p] == ' ' {
p++
}
v = v[p:]
}
if len(v) > 0 {
f("cookie", v)
}
}
continue
}
for _, v := range vv {
f(k, v)
}
}
if shouldSendReqContentLength(req.Method, contentLength) {
f("content-length", strconv.FormatInt(contentLength, 10))
}
if addGzipHeader {
f("accept-encoding", "gzip")
}
if !didUA {
f("user-agent", defaultUserAgent)
}
}
// Do a first pass over the headers counting bytes to ensure
// we don't exceed cc.peerMaxHeaderListSize. This is done as a
// separate pass before encoding the headers to prevent
// modifying the hpack state.
hlSize := uint64(0)
enumerateHeaders(func(name, value string) {
hf := hpack.HeaderField{Name: name, Value: value}
hlSize += uint64(hf.Size())
})
if hlSize > cc.peerMaxHeaderListSize {
return nil, errRequestHeaderListSize
}
trace := httptrace.ContextClientTrace(req.Context())
traceHeaders := traceHasWroteHeaderField(trace)
// Header list size is ok. Write the headers.
enumerateHeaders(func(name, value string) {
name, ascii := lowerHeader(name)
if !ascii {
// Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
// field names have to be ASCII characters (just as in HTTP/1.x).
return
}
cc.writeHeader(name, value)
if traceHeaders {
traceWroteHeaderField(trace, name, value)
}
})
return cc.hbuf.Bytes(), nil
}
// shouldSendReqContentLength reports whether the http2.Transport should send
// a "content-length" request header. This logic is basically a copy of the net/http
// transferWriter.shouldSendContentLength.
// The contentLength is the corrected contentLength (so 0 means actually 0, not unknown).
// -1 means unknown.
func shouldSendReqContentLength(method string, contentLength int64) bool {
if contentLength > 0 {
return true
}
if contentLength < 0 {
return false
}
// For zero bodies, whether we send a content-length depends on the method.
// It also kinda doesn't matter for http2 either way, with END_STREAM.
switch method {
case "POST", "PUT", "PATCH":
return true
default:
return false
}
}
// requires cc.wmu be held. // requires cc.wmu be held.
func (cc *ClientConn) encodeTrailers(trailer http.Header) ([]byte, error) { func (cc *ClientConn) encodeTrailers(trailer http.Header) ([]byte, error) {
cc.hbuf.Reset() cc.hbuf.Reset()
@ -2294,7 +2044,7 @@ func (cc *ClientConn) encodeTrailers(trailer http.Header) ([]byte, error) {
} }
for k, vv := range trailer { for k, vv := range trailer {
lowKey, ascii := lowerHeader(k) lowKey, ascii := httpcommon.LowerHeader(k)
if !ascii { if !ascii {
// Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header // Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
// field names have to be ASCII characters (just as in HTTP/1.x). // field names have to be ASCII characters (just as in HTTP/1.x).
@ -2434,9 +2184,12 @@ func (rl *clientConnReadLoop) cleanup() {
// This avoids a situation where new connections are constantly created, // This avoids a situation where new connections are constantly created,
// added to the pool, fail, and are removed from the pool, without any error // added to the pool, fail, and are removed from the pool, without any error
// being surfaced to the user. // being surfaced to the user.
const unusedWaitTime = 5 * time.Second unusedWaitTime := 5 * time.Second
if cc.idleTimeout > 0 && unusedWaitTime > cc.idleTimeout {
unusedWaitTime = cc.idleTimeout
}
idleTime := cc.t.now().Sub(cc.lastActive) idleTime := cc.t.now().Sub(cc.lastActive)
if atomic.LoadUint32(&cc.atomicReused) == 0 && idleTime < unusedWaitTime { if atomic.LoadUint32(&cc.atomicReused) == 0 && idleTime < unusedWaitTime && !cc.closedOnIdle {
cc.idleTimer = cc.t.afterFunc(unusedWaitTime-idleTime, func() { cc.idleTimer = cc.t.afterFunc(unusedWaitTime-idleTime, func() {
cc.t.connPool().MarkDead(cc) cc.t.connPool().MarkDead(cc)
}) })
@ -2457,6 +2210,13 @@ func (rl *clientConnReadLoop) cleanup() {
} }
cc.cond.Broadcast() cc.cond.Broadcast()
cc.mu.Unlock() cc.mu.Unlock()
if !cc.seenSettings {
// If we have a pending request that wants extended CONNECT,
// let it continue and fail with the connection error.
cc.extendedConnectAllowed = true
close(cc.seenSettingsChan)
}
} }
// countReadFrameError calls Transport.CountError with a string // countReadFrameError calls Transport.CountError with a string
@ -2549,9 +2309,6 @@ func (rl *clientConnReadLoop) run() error {
if VerboseLogs { if VerboseLogs {
cc.vlogf("http2: Transport conn %p received error from processing frame %v: %v", cc, summarizeFrame(f), err) cc.vlogf("http2: Transport conn %p received error from processing frame %v: %v", cc, summarizeFrame(f), err)
} }
if !cc.seenSettings {
close(cc.seenSettingsChan)
}
return err return err
} }
} }
@ -2646,7 +2403,7 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra
Status: status + " " + http.StatusText(statusCode), Status: status + " " + http.StatusText(statusCode),
} }
for _, hf := range regularFields { for _, hf := range regularFields {
key := canonicalHeader(hf.Name) key := httpcommon.CanonicalHeader(hf.Name)
if key == "Trailer" { if key == "Trailer" {
t := res.Trailer t := res.Trailer
if t == nil { if t == nil {
@ -2654,7 +2411,7 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra
res.Trailer = t res.Trailer = t
} }
foreachHeaderElement(hf.Value, func(v string) { foreachHeaderElement(hf.Value, func(v string) {
t[canonicalHeader(v)] = nil t[httpcommon.CanonicalHeader(v)] = nil
}) })
} else { } else {
vv := header[key] vv := header[key]
@ -2778,7 +2535,7 @@ func (rl *clientConnReadLoop) processTrailers(cs *clientStream, f *MetaHeadersFr
trailer := make(http.Header) trailer := make(http.Header)
for _, hf := range f.RegularFields() { for _, hf := range f.RegularFields() {
key := canonicalHeader(hf.Name) key := httpcommon.CanonicalHeader(hf.Name)
trailer[key] = append(trailer[key], hf.Value) trailer[key] = append(trailer[key], hf.Value)
} }
cs.trailer = trailer cs.trailer = trailer
@ -3324,7 +3081,7 @@ func (cc *ClientConn) writeStreamReset(streamID uint32, code ErrCode, ping bool,
var ( var (
errResponseHeaderListSize = errors.New("http2: response header list larger than advertised limit") errResponseHeaderListSize = errors.New("http2: response header list larger than advertised limit")
errRequestHeaderListSize = errors.New("http2: request header list larger than peer's advertised limit") errRequestHeaderListSize = httpcommon.ErrRequestHeaderListSize
) )
func (cc *ClientConn) logf(format string, args ...interface{}) { func (cc *ClientConn) logf(format string, args ...interface{}) {
@ -3508,16 +3265,6 @@ func traceFirstResponseByte(trace *httptrace.ClientTrace) {
} }
} }
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 { func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error {
if trace != nil { if trace != nil {
return trace.Got1xxResponse return trace.Got1xxResponse

View File

@ -13,6 +13,7 @@ import (
"golang.org/x/net/http/httpguts" "golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack" "golang.org/x/net/http2/hpack"
"golang.org/x/net/internal/httpcommon"
) )
// writeFramer is implemented by any type that is used to write frames. // writeFramer is implemented by any type that is used to write frames.
@ -351,7 +352,7 @@ func encodeHeaders(enc *hpack.Encoder, h http.Header, keys []string) {
} }
for _, k := range keys { for _, k := range keys {
vv := h[k] vv := h[k]
k, ascii := lowerHeader(k) k, ascii := httpcommon.LowerHeader(k)
if !ascii { if !ascii {
// Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header // Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
// field names have to be ASCII characters (just as in HTTP/1.x). // field names have to be ASCII characters (just as in HTTP/1.x).

53
vendor/golang.org/x/net/internal/httpcommon/ascii.go generated vendored Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2025 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 httpcommon
import "strings"
// The HTTP protocols are defined in terms of ASCII, not Unicode. This file
// contains helper functions which may use Unicode-aware functions which would
// otherwise be unsafe and could introduce vulnerabilities if used improperly.
// asciiEqualFold is strings.EqualFold, ASCII only. It reports whether s and t
// are equal, ASCII-case-insensitively.
func asciiEqualFold(s, t string) bool {
if len(s) != len(t) {
return false
}
for i := 0; i < len(s); i++ {
if lower(s[i]) != lower(t[i]) {
return false
}
}
return true
}
// lower returns the ASCII lowercase version of b.
func lower(b byte) byte {
if 'A' <= b && b <= 'Z' {
return b + ('a' - 'A')
}
return b
}
// isASCIIPrint returns whether s is ASCII and printable according to
// https://tools.ietf.org/html/rfc20#section-4.2.
func isASCIIPrint(s string) bool {
for i := 0; i < len(s); i++ {
if s[i] < ' ' || s[i] > '~' {
return false
}
}
return true
}
// asciiToLower returns the lowercase version of s if s is ASCII and printable,
// and whether or not it was.
func asciiToLower(s string) (lower string, ok bool) {
if !isASCIIPrint(s) {
return "", false
}
return strings.ToLower(s), true
}

View File

@ -1,11 +1,11 @@
// Copyright 2014 The Go Authors. All rights reserved. // Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package http2 package httpcommon
import ( import (
"net/http" "net/textproto"
"sync" "sync"
) )
@ -82,13 +82,15 @@ func buildCommonHeaderMaps() {
commonLowerHeader = make(map[string]string, len(common)) commonLowerHeader = make(map[string]string, len(common))
commonCanonHeader = make(map[string]string, len(common)) commonCanonHeader = make(map[string]string, len(common))
for _, v := range common { for _, v := range common {
chk := http.CanonicalHeaderKey(v) chk := textproto.CanonicalMIMEHeaderKey(v)
commonLowerHeader[chk] = v commonLowerHeader[chk] = v
commonCanonHeader[v] = chk commonCanonHeader[v] = chk
} }
} }
func lowerHeader(v string) (lower string, ascii bool) { // LowerHeader returns the lowercase form of a header name,
// used on the wire for HTTP/2 and HTTP/3 requests.
func LowerHeader(v string) (lower string, ascii bool) {
buildCommonHeaderMapsOnce() buildCommonHeaderMapsOnce()
if s, ok := commonLowerHeader[v]; ok { if s, ok := commonLowerHeader[v]; ok {
return s, true return s, true
@ -96,10 +98,18 @@ func lowerHeader(v string) (lower string, ascii bool) {
return asciiToLower(v) return asciiToLower(v)
} }
func canonicalHeader(v string) string { // CanonicalHeader canonicalizes a header name. (For example, "host" becomes "Host".)
func CanonicalHeader(v string) string {
buildCommonHeaderMapsOnce() buildCommonHeaderMapsOnce()
if s, ok := commonCanonHeader[v]; ok { if s, ok := commonCanonHeader[v]; ok {
return s return s
} }
return http.CanonicalHeaderKey(v) return textproto.CanonicalMIMEHeaderKey(v)
}
// CachedCanonicalHeader returns the canonical form of a well-known header name.
func CachedCanonicalHeader(v string) (string, bool) {
buildCommonHeaderMapsOnce()
s, ok := commonCanonHeader[v]
return s, ok
} }

467
vendor/golang.org/x/net/internal/httpcommon/request.go generated vendored Normal file
View File

@ -0,0 +1,467 @@
// Copyright 2025 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 httpcommon
import (
"context"
"errors"
"fmt"
"net/http/httptrace"
"net/textproto"
"net/url"
"sort"
"strconv"
"strings"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack"
)
var (
ErrRequestHeaderListSize = errors.New("request header list larger than peer's advertised limit")
)
// Request is a subset of http.Request.
// It'd be simpler to pass an *http.Request, of course, but we can't depend on net/http
// without creating a dependency cycle.
type Request struct {
URL *url.URL
Method string
Host string
Header map[string][]string
Trailer map[string][]string
ActualContentLength int64 // 0 means 0, -1 means unknown
}
// EncodeHeadersParam is parameters to EncodeHeaders.
type EncodeHeadersParam struct {
Request Request
// AddGzipHeader indicates that an "accept-encoding: gzip" header should be
// added to the request.
AddGzipHeader bool
// PeerMaxHeaderListSize, when non-zero, is the peer's MAX_HEADER_LIST_SIZE setting.
PeerMaxHeaderListSize uint64
// DefaultUserAgent is the User-Agent header to send when the request
// neither contains a User-Agent nor disables it.
DefaultUserAgent string
}
// EncodeHeadersParam is the result of EncodeHeaders.
type EncodeHeadersResult struct {
HasBody bool
HasTrailers bool
}
// EncodeHeaders constructs request headers common to HTTP/2 and HTTP/3.
// It validates a request and calls headerf with each pseudo-header and header
// for the request.
// The headerf function is called with the validated, canonicalized header name.
func EncodeHeaders(ctx context.Context, param EncodeHeadersParam, headerf func(name, value string)) (res EncodeHeadersResult, _ error) {
req := param.Request
// Check for invalid connection-level headers.
if err := checkConnHeaders(req.Header); err != nil {
return res, err
}
if req.URL == nil {
return res, errors.New("Request.URL is nil")
}
host := req.Host
if host == "" {
host = req.URL.Host
}
host, err := httpguts.PunycodeHostPort(host)
if err != nil {
return res, err
}
if !httpguts.ValidHostHeader(host) {
return res, errors.New("invalid Host header")
}
// isNormalConnect is true if this is a non-extended CONNECT request.
isNormalConnect := false
var protocol string
if vv := req.Header[":protocol"]; len(vv) > 0 {
protocol = vv[0]
}
if req.Method == "CONNECT" && protocol == "" {
isNormalConnect = true
} else if protocol != "" && req.Method != "CONNECT" {
return res, errors.New("invalid :protocol header in non-CONNECT request")
}
// Validate the path, except for non-extended CONNECT requests which have no path.
var path string
if !isNormalConnect {
path = req.URL.RequestURI()
if !validPseudoPath(path) {
orig := path
path = strings.TrimPrefix(path, req.URL.Scheme+"://"+host)
if !validPseudoPath(path) {
if req.URL.Opaque != "" {
return res, fmt.Errorf("invalid request :path %q from URL.Opaque = %q", orig, req.URL.Opaque)
} else {
return res, fmt.Errorf("invalid request :path %q", orig)
}
}
}
}
// Check for any invalid headers+trailers 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 res, fmt.Errorf("invalid HTTP header %s", err)
}
if err := validateHeaders(req.Trailer); err != "" {
return res, fmt.Errorf("invalid HTTP trailer %s", err)
}
trailers, err := commaSeparatedTrailers(req.Trailer)
if err != nil {
return res, err
}
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
// [RFC3986]).
f(":authority", host)
m := req.Method
if m == "" {
m = "GET"
}
f(":method", m)
if !isNormalConnect {
f(":path", path)
f(":scheme", req.URL.Scheme)
}
if protocol != "" {
f(":protocol", protocol)
}
if trailers != "" {
f("trailer", trailers)
}
var didUA bool
for k, vv := range req.Header {
if asciiEqualFold(k, "host") || asciiEqualFold(k, "content-length") {
// Host is :authority, already sent.
// Content-Length is automatic, set below.
continue
} else if asciiEqualFold(k, "connection") ||
asciiEqualFold(k, "proxy-connection") ||
asciiEqualFold(k, "transfer-encoding") ||
asciiEqualFold(k, "upgrade") ||
asciiEqualFold(k, "keep-alive") {
// Per 8.1.2.2 Connection-Specific Header
// Fields, don't send connection-specific
// fields. We have already checked if any
// are error-worthy so just ignore the rest.
continue
} else if asciiEqualFold(k, "user-agent") {
// Match Go's http1 behavior: at most one
// User-Agent. If set to nil or empty string,
// then omit it. Otherwise if not mentioned,
// include the default (below).
didUA = true
if len(vv) < 1 {
continue
}
vv = vv[:1]
if vv[0] == "" {
continue
}
} else if asciiEqualFold(k, "cookie") {
// Per 8.1.2.5 To allow for better compression efficiency, the
// Cookie header field MAY be split into separate header fields,
// each with one or more cookie-pairs.
for _, v := range vv {
for {
p := strings.IndexByte(v, ';')
if p < 0 {
break
}
f("cookie", v[:p])
p++
// strip space after semicolon if any.
for p+1 <= len(v) && v[p] == ' ' {
p++
}
v = v[p:]
}
if len(v) > 0 {
f("cookie", v)
}
}
continue
} else if k == ":protocol" {
// :protocol pseudo-header was already sent above.
continue
}
for _, v := range vv {
f(k, v)
}
}
if shouldSendReqContentLength(req.Method, req.ActualContentLength) {
f("content-length", strconv.FormatInt(req.ActualContentLength, 10))
}
if param.AddGzipHeader {
f("accept-encoding", "gzip")
}
if !didUA {
f("user-agent", param.DefaultUserAgent)
}
}
// Do a first pass over the headers counting bytes to ensure
// we don't exceed cc.peerMaxHeaderListSize. This is done as a
// separate pass before encoding the headers to prevent
// modifying the hpack state.
if param.PeerMaxHeaderListSize > 0 {
hlSize := uint64(0)
enumerateHeaders(func(name, value string) {
hf := hpack.HeaderField{Name: name, Value: value}
hlSize += uint64(hf.Size())
})
if hlSize > param.PeerMaxHeaderListSize {
return res, ErrRequestHeaderListSize
}
}
trace := httptrace.ContextClientTrace(ctx)
// Header list size is ok. Write the headers.
enumerateHeaders(func(name, value string) {
name, ascii := LowerHeader(name)
if !ascii {
// Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header
// field names have to be ASCII characters (just as in HTTP/1.x).
return
}
headerf(name, value)
if trace != nil && trace.WroteHeaderField != nil {
trace.WroteHeaderField(name, []string{value})
}
})
res.HasBody = req.ActualContentLength != 0
res.HasTrailers = trailers != ""
return res, nil
}
// IsRequestGzip reports whether we should add an Accept-Encoding: gzip header
// for a request.
func IsRequestGzip(method string, header map[string][]string, disableCompression bool) bool {
// TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere?
if !disableCompression &&
len(header["Accept-Encoding"]) == 0 &&
len(header["Range"]) == 0 &&
method != "HEAD" {
// Request gzip only, not deflate. Deflate is ambiguous and
// not as universally supported anyway.
// See: https://zlib.net/zlib_faq.html#faq39
//
// Note that we don't request this for HEAD requests,
// due to a bug in nginx:
// http://trac.nginx.org/nginx/ticket/358
// https://golang.org/issue/5522
//
// We don't request gzip if the request is for a range, since
// auto-decoding a portion of a gzipped document will just fail
// anyway. See https://golang.org/issue/8923
return true
}
return false
}
// checkConnHeaders checks whether req has any invalid connection-level headers.
//
// https://www.rfc-editor.org/rfc/rfc9114.html#section-4.2-3
// https://www.rfc-editor.org/rfc/rfc9113.html#section-8.2.2-1
//
// Certain headers are special-cased as okay but not transmitted later.
// For example, we allow "Transfer-Encoding: chunked", but drop the header when encoding.
func checkConnHeaders(h map[string][]string) error {
if vv := h["Upgrade"]; len(vv) > 0 && (vv[0] != "" && vv[0] != "chunked") {
return fmt.Errorf("invalid Upgrade request header: %q", vv)
}
if vv := h["Transfer-Encoding"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && vv[0] != "chunked") {
return fmt.Errorf("invalid Transfer-Encoding request header: %q", vv)
}
if vv := h["Connection"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && !asciiEqualFold(vv[0], "close") && !asciiEqualFold(vv[0], "keep-alive")) {
return fmt.Errorf("invalid Connection request header: %q", vv)
}
return nil
}
func commaSeparatedTrailers(trailer map[string][]string) (string, error) {
keys := make([]string, 0, len(trailer))
for k := range trailer {
k = CanonicalHeader(k)
switch k {
case "Transfer-Encoding", "Trailer", "Content-Length":
return "", fmt.Errorf("invalid Trailer key %q", k)
}
keys = append(keys, k)
}
if len(keys) > 0 {
sort.Strings(keys)
return strings.Join(keys, ","), nil
}
return "", nil
}
// validPseudoPath reports whether v is a valid :path pseudo-header
// value. It must be either:
//
// - a non-empty string starting with '/'
// - the string '*', for OPTIONS requests.
//
// For now this is only used a quick check for deciding when to clean
// up Opaque URLs before sending requests from the Transport.
// See golang.org/issue/16847
//
// We used to enforce that the path also didn't start with "//", but
// Google's GFE accepts such paths and Chrome sends them, so ignore
// that part of the spec. See golang.org/issue/19103.
func validPseudoPath(v string) bool {
return (len(v) > 0 && v[0] == '/') || v == "*"
}
func validateHeaders(hdrs map[string][]string) string {
for k, vv := range hdrs {
if !httpguts.ValidHeaderFieldName(k) && k != ":protocol" {
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 ""
}
// shouldSendReqContentLength reports whether we should send
// a "content-length" request header. This logic is basically a copy of the net/http
// transferWriter.shouldSendContentLength.
// The contentLength is the corrected contentLength (so 0 means actually 0, not unknown).
// -1 means unknown.
func shouldSendReqContentLength(method string, contentLength int64) bool {
if contentLength > 0 {
return true
}
if contentLength < 0 {
return false
}
// For zero bodies, whether we send a content-length depends on the method.
// It also kinda doesn't matter for http2 either way, with END_STREAM.
switch method {
case "POST", "PUT", "PATCH":
return true
default:
return false
}
}
// ServerRequestParam is parameters to NewServerRequest.
type ServerRequestParam struct {
Method string
Scheme, Authority, Path string
Protocol string
Header map[string][]string
}
// ServerRequestResult is the result of NewServerRequest.
type ServerRequestResult struct {
// Various http.Request fields.
URL *url.URL
RequestURI string
Trailer map[string][]string
NeedsContinue bool // client provided an "Expect: 100-continue" header
// If the request should be rejected, this is a short string suitable for passing
// to the http2 package's CountError function.
// It might be a bit odd to return errors this way rather than returing an error,
// but this ensures we don't forget to include a CountError reason.
InvalidReason string
}
func NewServerRequest(rp ServerRequestParam) ServerRequestResult {
needsContinue := httpguts.HeaderValuesContainsToken(rp.Header["Expect"], "100-continue")
if needsContinue {
delete(rp.Header, "Expect")
}
// Merge Cookie headers into one "; "-delimited value.
if cookies := rp.Header["Cookie"]; len(cookies) > 1 {
rp.Header["Cookie"] = []string{strings.Join(cookies, "; ")}
}
// Setup Trailers
var trailer map[string][]string
for _, v := range rp.Header["Trailer"] {
for _, key := range strings.Split(v, ",") {
key = textproto.CanonicalMIMEHeaderKey(textproto.TrimString(key))
switch key {
case "Transfer-Encoding", "Trailer", "Content-Length":
// Bogus. (copy of http1 rules)
// Ignore.
default:
if trailer == nil {
trailer = make(map[string][]string)
}
trailer[key] = nil
}
}
}
delete(rp.Header, "Trailer")
// "':authority' MUST NOT include the deprecated userinfo subcomponent
// for "http" or "https" schemed URIs."
// https://www.rfc-editor.org/rfc/rfc9113.html#section-8.3.1-2.3.8
if strings.IndexByte(rp.Authority, '@') != -1 && (rp.Scheme == "http" || rp.Scheme == "https") {
return ServerRequestResult{
InvalidReason: "userinfo_in_authority",
}
}
var url_ *url.URL
var requestURI string
if rp.Method == "CONNECT" && rp.Protocol == "" {
url_ = &url.URL{Host: rp.Authority}
requestURI = rp.Authority // mimic HTTP/1 server behavior
} else {
var err error
url_, err = url.ParseRequestURI(rp.Path)
if err != nil {
return ServerRequestResult{
InvalidReason: "bad_path",
}
}
requestURI = rp.Path
}
return ServerRequestResult{
URL: url_,
NeedsContinue: needsContinue,
RequestURI: requestURI,
Trailer: trailer,
}
}

View File

@ -18,7 +18,7 @@ import (
type token struct{} type token struct{}
// A Group is a collection of goroutines working on subtasks that are part of // A Group is a collection of goroutines working on subtasks that are part of
// the same overall task. // the same overall task. A Group should not be reused for different tasks.
// //
// A zero Group is valid, has no limit on the number of active goroutines, // A zero Group is valid, has no limit on the number of active goroutines,
// and does not cancel on error. // and does not cancel on error.
@ -46,7 +46,7 @@ func (g *Group) done() {
// returns a non-nil error or the first time Wait returns, whichever occurs // returns a non-nil error or the first time Wait returns, whichever occurs
// first. // first.
func WithContext(ctx context.Context) (*Group, context.Context) { func WithContext(ctx context.Context) (*Group, context.Context) {
ctx, cancel := withCancelCause(ctx) ctx, cancel := context.WithCancelCause(ctx)
return &Group{cancel: cancel}, ctx return &Group{cancel: cancel}, ctx
} }
@ -61,6 +61,7 @@ func (g *Group) Wait() error {
} }
// Go calls the given function in a new goroutine. // Go calls the given function in a new goroutine.
// The first call to Go must happen before a Wait.
// It blocks until the new goroutine can be added without the number of // It blocks until the new goroutine can be added without the number of
// active goroutines in the group exceeding the configured limit. // active goroutines in the group exceeding the configured limit.
// //

View File

@ -1,13 +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.
//go:build go1.20
package errgroup
import "context"
func withCancelCause(parent context.Context) (context.Context, func(error)) {
return context.WithCancelCause(parent)
}

View File

@ -1,14 +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.
//go:build !go1.20
package errgroup
import "context"
func withCancelCause(parent context.Context) (context.Context, func(error)) {
ctx, cancel := context.WithCancel(parent)
return ctx, func(error) { cancel() }
}

View File

@ -602,7 +602,150 @@ func Connectx(fd int, srcIf uint32, srcAddr, dstAddr Sockaddr, associd SaeAssocI
return return
} }
//sys connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error) // sys connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error)
const minIovec = 8
func Readv(fd int, iovs [][]byte) (n int, err error) {
if !darwinKernelVersionMin(11, 0, 0) {
return 0, ENOSYS
}
iovecs := make([]Iovec, 0, minIovec)
iovecs = appendBytes(iovecs, iovs)
n, err = readv(fd, iovecs)
readvRacedetect(iovecs, n, err)
return n, err
}
func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) {
if !darwinKernelVersionMin(11, 0, 0) {
return 0, ENOSYS
}
iovecs := make([]Iovec, 0, minIovec)
iovecs = appendBytes(iovecs, iovs)
n, err = preadv(fd, iovecs, offset)
readvRacedetect(iovecs, n, err)
return n, err
}
func Writev(fd int, iovs [][]byte) (n int, err error) {
if !darwinKernelVersionMin(11, 0, 0) {
return 0, ENOSYS
}
iovecs := make([]Iovec, 0, minIovec)
iovecs = appendBytes(iovecs, iovs)
if raceenabled {
raceReleaseMerge(unsafe.Pointer(&ioSync))
}
n, err = writev(fd, iovecs)
writevRacedetect(iovecs, n)
return n, err
}
func Pwritev(fd int, iovs [][]byte, offset int64) (n int, err error) {
if !darwinKernelVersionMin(11, 0, 0) {
return 0, ENOSYS
}
iovecs := make([]Iovec, 0, minIovec)
iovecs = appendBytes(iovecs, iovs)
if raceenabled {
raceReleaseMerge(unsafe.Pointer(&ioSync))
}
n, err = pwritev(fd, iovecs, offset)
writevRacedetect(iovecs, n)
return n, err
}
func appendBytes(vecs []Iovec, bs [][]byte) []Iovec {
for _, b := range bs {
var v Iovec
v.SetLen(len(b))
if len(b) > 0 {
v.Base = &b[0]
} else {
v.Base = (*byte)(unsafe.Pointer(&_zero))
}
vecs = append(vecs, v)
}
return vecs
}
func writevRacedetect(iovecs []Iovec, n int) {
if !raceenabled {
return
}
for i := 0; n > 0 && i < len(iovecs); i++ {
m := int(iovecs[i].Len)
if m > n {
m = n
}
n -= m
if m > 0 {
raceReadRange(unsafe.Pointer(iovecs[i].Base), m)
}
}
}
func readvRacedetect(iovecs []Iovec, n int, err error) {
if !raceenabled {
return
}
for i := 0; n > 0 && i < len(iovecs); i++ {
m := int(iovecs[i].Len)
if m > n {
m = n
}
n -= m
if m > 0 {
raceWriteRange(unsafe.Pointer(iovecs[i].Base), m)
}
}
if err == nil {
raceAcquire(unsafe.Pointer(&ioSync))
}
}
func darwinMajorMinPatch() (maj, min, patch int, err error) {
var un Utsname
err = Uname(&un)
if err != nil {
return
}
var mmp [3]int
c := 0
Loop:
for _, b := range un.Release[:] {
switch {
case b >= '0' && b <= '9':
mmp[c] = 10*mmp[c] + int(b-'0')
case b == '.':
c++
if c > 2 {
return 0, 0, 0, ENOTSUP
}
case b == 0:
break Loop
default:
return 0, 0, 0, ENOTSUP
}
}
if c != 2 {
return 0, 0, 0, ENOTSUP
}
return mmp[0], mmp[1], mmp[2], nil
}
func darwinKernelVersionMin(maj, min, patch int) bool {
actualMaj, actualMin, actualPatch, err := darwinMajorMinPatch()
if err != nil {
return false
}
return actualMaj > maj || actualMaj == maj && (actualMin > min || actualMin == min && actualPatch >= patch)
}
//sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) //sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error)
//sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error) //sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error)
@ -705,3 +848,7 @@ func Connectx(fd int, srcIf uint32, srcAddr, dstAddr Sockaddr, associd SaeAssocI
//sys write(fd int, p []byte) (n int, err error) //sys write(fd int, p []byte) (n int, err error)
//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) //sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
//sys munmap(addr uintptr, length uintptr) (err error) //sys munmap(addr uintptr, length uintptr) (err error)
//sys readv(fd int, iovecs []Iovec) (n int, err error)
//sys preadv(fd int, iovecs []Iovec, offset int64) (n int, err error)
//sys writev(fd int, iovecs []Iovec) (n int, err error)
//sys pwritev(fd int, iovecs []Iovec, offset int64) (n int, err error)

View File

@ -13,6 +13,7 @@ package unix
import ( import (
"encoding/binary" "encoding/binary"
"slices"
"strconv" "strconv"
"syscall" "syscall"
"time" "time"
@ -417,7 +418,7 @@ func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
return nil, 0, EINVAL return nil, 0, EINVAL
} }
sa.raw.Family = AF_UNIX sa.raw.Family = AF_UNIX
for i := 0; i < n; i++ { for i := range n {
sa.raw.Path[i] = int8(name[i]) sa.raw.Path[i] = int8(name[i])
} }
// length is family (uint16), name, NUL. // length is family (uint16), name, NUL.
@ -507,7 +508,7 @@ func (sa *SockaddrL2) sockaddr() (unsafe.Pointer, _Socklen, error) {
psm := (*[2]byte)(unsafe.Pointer(&sa.raw.Psm)) psm := (*[2]byte)(unsafe.Pointer(&sa.raw.Psm))
psm[0] = byte(sa.PSM) psm[0] = byte(sa.PSM)
psm[1] = byte(sa.PSM >> 8) psm[1] = byte(sa.PSM >> 8)
for i := 0; i < len(sa.Addr); i++ { for i := range len(sa.Addr) {
sa.raw.Bdaddr[i] = sa.Addr[len(sa.Addr)-1-i] sa.raw.Bdaddr[i] = sa.Addr[len(sa.Addr)-1-i]
} }
cid := (*[2]byte)(unsafe.Pointer(&sa.raw.Cid)) cid := (*[2]byte)(unsafe.Pointer(&sa.raw.Cid))
@ -589,11 +590,11 @@ func (sa *SockaddrCAN) sockaddr() (unsafe.Pointer, _Socklen, error) {
sa.raw.Family = AF_CAN sa.raw.Family = AF_CAN
sa.raw.Ifindex = int32(sa.Ifindex) sa.raw.Ifindex = int32(sa.Ifindex)
rx := (*[4]byte)(unsafe.Pointer(&sa.RxID)) rx := (*[4]byte)(unsafe.Pointer(&sa.RxID))
for i := 0; i < 4; i++ { for i := range 4 {
sa.raw.Addr[i] = rx[i] sa.raw.Addr[i] = rx[i]
} }
tx := (*[4]byte)(unsafe.Pointer(&sa.TxID)) tx := (*[4]byte)(unsafe.Pointer(&sa.TxID))
for i := 0; i < 4; i++ { for i := range 4 {
sa.raw.Addr[i+4] = tx[i] sa.raw.Addr[i+4] = tx[i]
} }
return unsafe.Pointer(&sa.raw), SizeofSockaddrCAN, nil return unsafe.Pointer(&sa.raw), SizeofSockaddrCAN, nil
@ -618,11 +619,11 @@ func (sa *SockaddrCANJ1939) sockaddr() (unsafe.Pointer, _Socklen, error) {
sa.raw.Family = AF_CAN sa.raw.Family = AF_CAN
sa.raw.Ifindex = int32(sa.Ifindex) sa.raw.Ifindex = int32(sa.Ifindex)
n := (*[8]byte)(unsafe.Pointer(&sa.Name)) n := (*[8]byte)(unsafe.Pointer(&sa.Name))
for i := 0; i < 8; i++ { for i := range 8 {
sa.raw.Addr[i] = n[i] sa.raw.Addr[i] = n[i]
} }
p := (*[4]byte)(unsafe.Pointer(&sa.PGN)) p := (*[4]byte)(unsafe.Pointer(&sa.PGN))
for i := 0; i < 4; i++ { for i := range 4 {
sa.raw.Addr[i+8] = p[i] sa.raw.Addr[i+8] = p[i]
} }
sa.raw.Addr[12] = sa.Addr sa.raw.Addr[12] = sa.Addr
@ -911,7 +912,7 @@ func (sa *SockaddrIUCV) sockaddr() (unsafe.Pointer, _Socklen, error) {
// These are EBCDIC encoded by the kernel, but we still need to pad them // These are EBCDIC encoded by the kernel, but we still need to pad them
// with blanks. Initializing with blanks allows the caller to feed in either // with blanks. Initializing with blanks allows the caller to feed in either
// a padded or an unpadded string. // a padded or an unpadded string.
for i := 0; i < 8; i++ { for i := range 8 {
sa.raw.Nodeid[i] = ' ' sa.raw.Nodeid[i] = ' '
sa.raw.User_id[i] = ' ' sa.raw.User_id[i] = ' '
sa.raw.Name[i] = ' ' sa.raw.Name[i] = ' '
@ -1148,7 +1149,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
var user [8]byte var user [8]byte
var name [8]byte var name [8]byte
for i := 0; i < 8; i++ { for i := range 8 {
user[i] = byte(pp.User_id[i]) user[i] = byte(pp.User_id[i])
name[i] = byte(pp.Name[i]) name[i] = byte(pp.Name[i])
} }
@ -1173,11 +1174,11 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
Ifindex: int(pp.Ifindex), Ifindex: int(pp.Ifindex),
} }
name := (*[8]byte)(unsafe.Pointer(&sa.Name)) name := (*[8]byte)(unsafe.Pointer(&sa.Name))
for i := 0; i < 8; i++ { for i := range 8 {
name[i] = pp.Addr[i] name[i] = pp.Addr[i]
} }
pgn := (*[4]byte)(unsafe.Pointer(&sa.PGN)) pgn := (*[4]byte)(unsafe.Pointer(&sa.PGN))
for i := 0; i < 4; i++ { for i := range 4 {
pgn[i] = pp.Addr[i+8] pgn[i] = pp.Addr[i+8]
} }
addr := (*[1]byte)(unsafe.Pointer(&sa.Addr)) addr := (*[1]byte)(unsafe.Pointer(&sa.Addr))
@ -1188,11 +1189,11 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
Ifindex: int(pp.Ifindex), Ifindex: int(pp.Ifindex),
} }
rx := (*[4]byte)(unsafe.Pointer(&sa.RxID)) rx := (*[4]byte)(unsafe.Pointer(&sa.RxID))
for i := 0; i < 4; i++ { for i := range 4 {
rx[i] = pp.Addr[i] rx[i] = pp.Addr[i]
} }
tx := (*[4]byte)(unsafe.Pointer(&sa.TxID)) tx := (*[4]byte)(unsafe.Pointer(&sa.TxID))
for i := 0; i < 4; i++ { for i := range 4 {
tx[i] = pp.Addr[i+4] tx[i] = pp.Addr[i+4]
} }
return sa, nil return sa, nil
@ -2216,10 +2217,7 @@ func readvRacedetect(iovecs []Iovec, n int, err error) {
return return
} }
for i := 0; n > 0 && i < len(iovecs); i++ { for i := 0; n > 0 && i < len(iovecs); i++ {
m := int(iovecs[i].Len) m := min(int(iovecs[i].Len), n)
if m > n {
m = n
}
n -= m n -= m
if m > 0 { if m > 0 {
raceWriteRange(unsafe.Pointer(iovecs[i].Base), m) raceWriteRange(unsafe.Pointer(iovecs[i].Base), m)
@ -2270,10 +2268,7 @@ func writevRacedetect(iovecs []Iovec, n int) {
return return
} }
for i := 0; n > 0 && i < len(iovecs); i++ { for i := 0; n > 0 && i < len(iovecs); i++ {
m := int(iovecs[i].Len) m := min(int(iovecs[i].Len), n)
if m > n {
m = n
}
n -= m n -= m
if m > 0 { if m > 0 {
raceReadRange(unsafe.Pointer(iovecs[i].Base), m) raceReadRange(unsafe.Pointer(iovecs[i].Base), m)
@ -2320,12 +2315,7 @@ func isGroupMember(gid int) bool {
return false return false
} }
for _, g := range groups { return slices.Contains(groups, gid)
if g == gid {
return true
}
}
return false
} }
func isCapDacOverrideSet() bool { func isCapDacOverrideSet() bool {

View File

@ -2512,6 +2512,90 @@ var libc_munmap_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func readv(fd int, iovecs []Iovec) (n int, err error) {
var _p0 unsafe.Pointer
if len(iovecs) > 0 {
_p0 = unsafe.Pointer(&iovecs[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall_syscall(libc_readv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)))
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_readv_trampoline_addr uintptr
//go:cgo_import_dynamic libc_readv readv "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func preadv(fd int, iovecs []Iovec, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(iovecs) > 0 {
_p0 = unsafe.Pointer(&iovecs[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall_syscall6(libc_preadv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0)
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_preadv_trampoline_addr uintptr
//go:cgo_import_dynamic libc_preadv preadv "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func writev(fd int, iovecs []Iovec) (n int, err error) {
var _p0 unsafe.Pointer
if len(iovecs) > 0 {
_p0 = unsafe.Pointer(&iovecs[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall_syscall(libc_writev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)))
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_writev_trampoline_addr uintptr
//go:cgo_import_dynamic libc_writev writev "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func pwritev(fd int, iovecs []Iovec, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(iovecs) > 0 {
_p0 = unsafe.Pointer(&iovecs[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall_syscall6(libc_pwritev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0)
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_pwritev_trampoline_addr uintptr
//go:cgo_import_dynamic libc_pwritev pwritev "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fstat(fd int, stat *Stat_t) (err error) { func Fstat(fd int, stat *Stat_t) (err error) {
_, _, e1 := syscall_syscall(libc_fstat64_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) _, _, e1 := syscall_syscall(libc_fstat64_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
if e1 != 0 { if e1 != 0 {

View File

@ -738,6 +738,26 @@ TEXT libc_munmap_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_munmap_trampoline_addr(SB), RODATA, $8 GLOBL ·libc_munmap_trampoline_addr(SB), RODATA, $8
DATA ·libc_munmap_trampoline_addr(SB)/8, $libc_munmap_trampoline<>(SB) DATA ·libc_munmap_trampoline_addr(SB)/8, $libc_munmap_trampoline<>(SB)
TEXT libc_readv_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_readv(SB)
GLOBL ·libc_readv_trampoline_addr(SB), RODATA, $8
DATA ·libc_readv_trampoline_addr(SB)/8, $libc_readv_trampoline<>(SB)
TEXT libc_preadv_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_preadv(SB)
GLOBL ·libc_preadv_trampoline_addr(SB), RODATA, $8
DATA ·libc_preadv_trampoline_addr(SB)/8, $libc_preadv_trampoline<>(SB)
TEXT libc_writev_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_writev(SB)
GLOBL ·libc_writev_trampoline_addr(SB), RODATA, $8
DATA ·libc_writev_trampoline_addr(SB)/8, $libc_writev_trampoline<>(SB)
TEXT libc_pwritev_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_pwritev(SB)
GLOBL ·libc_pwritev_trampoline_addr(SB), RODATA, $8
DATA ·libc_pwritev_trampoline_addr(SB)/8, $libc_pwritev_trampoline<>(SB)
TEXT libc_fstat64_trampoline<>(SB),NOSPLIT,$0-0 TEXT libc_fstat64_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_fstat64(SB) JMP libc_fstat64(SB)
GLOBL ·libc_fstat64_trampoline_addr(SB), RODATA, $8 GLOBL ·libc_fstat64_trampoline_addr(SB), RODATA, $8

View File

@ -2512,6 +2512,90 @@ var libc_munmap_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func readv(fd int, iovecs []Iovec) (n int, err error) {
var _p0 unsafe.Pointer
if len(iovecs) > 0 {
_p0 = unsafe.Pointer(&iovecs[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall_syscall(libc_readv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)))
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_readv_trampoline_addr uintptr
//go:cgo_import_dynamic libc_readv readv "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func preadv(fd int, iovecs []Iovec, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(iovecs) > 0 {
_p0 = unsafe.Pointer(&iovecs[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall_syscall6(libc_preadv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0)
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_preadv_trampoline_addr uintptr
//go:cgo_import_dynamic libc_preadv preadv "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func writev(fd int, iovecs []Iovec) (n int, err error) {
var _p0 unsafe.Pointer
if len(iovecs) > 0 {
_p0 = unsafe.Pointer(&iovecs[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall_syscall(libc_writev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)))
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_writev_trampoline_addr uintptr
//go:cgo_import_dynamic libc_writev writev "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func pwritev(fd int, iovecs []Iovec, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(iovecs) > 0 {
_p0 = unsafe.Pointer(&iovecs[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := syscall_syscall6(libc_pwritev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0)
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_pwritev_trampoline_addr uintptr
//go:cgo_import_dynamic libc_pwritev pwritev "/usr/lib/libSystem.B.dylib"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fstat(fd int, stat *Stat_t) (err error) { func Fstat(fd int, stat *Stat_t) (err error) {
_, _, e1 := syscall_syscall(libc_fstat_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0) _, _, e1 := syscall_syscall(libc_fstat_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
if e1 != 0 { if e1 != 0 {

View File

@ -738,6 +738,26 @@ TEXT libc_munmap_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_munmap_trampoline_addr(SB), RODATA, $8 GLOBL ·libc_munmap_trampoline_addr(SB), RODATA, $8
DATA ·libc_munmap_trampoline_addr(SB)/8, $libc_munmap_trampoline<>(SB) DATA ·libc_munmap_trampoline_addr(SB)/8, $libc_munmap_trampoline<>(SB)
TEXT libc_readv_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_readv(SB)
GLOBL ·libc_readv_trampoline_addr(SB), RODATA, $8
DATA ·libc_readv_trampoline_addr(SB)/8, $libc_readv_trampoline<>(SB)
TEXT libc_preadv_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_preadv(SB)
GLOBL ·libc_preadv_trampoline_addr(SB), RODATA, $8
DATA ·libc_preadv_trampoline_addr(SB)/8, $libc_preadv_trampoline<>(SB)
TEXT libc_writev_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_writev(SB)
GLOBL ·libc_writev_trampoline_addr(SB), RODATA, $8
DATA ·libc_writev_trampoline_addr(SB)/8, $libc_writev_trampoline<>(SB)
TEXT libc_pwritev_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_pwritev(SB)
GLOBL ·libc_pwritev_trampoline_addr(SB), RODATA, $8
DATA ·libc_pwritev_trampoline_addr(SB)/8, $libc_pwritev_trampoline<>(SB)
TEXT libc_fstat_trampoline<>(SB),NOSPLIT,$0-0 TEXT libc_fstat_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_fstat(SB) JMP libc_fstat(SB)
GLOBL ·libc_fstat_trampoline_addr(SB), RODATA, $8 GLOBL ·libc_fstat_trampoline_addr(SB), RODATA, $8

View File

@ -164,7 +164,12 @@ loopItems:
func CreateKey(k Key, path string, access uint32) (newk Key, openedExisting bool, err error) { func CreateKey(k Key, path string, access uint32) (newk Key, openedExisting bool, err error) {
var h syscall.Handle var h syscall.Handle
var d uint32 var d uint32
err = regCreateKeyEx(syscall.Handle(k), syscall.StringToUTF16Ptr(path), var pathPointer *uint16
pathPointer, err = syscall.UTF16PtrFromString(path)
if err != nil {
return 0, false, err
}
err = regCreateKeyEx(syscall.Handle(k), pathPointer,
0, nil, _REG_OPTION_NON_VOLATILE, access, nil, &h, &d) 0, nil, _REG_OPTION_NON_VOLATILE, access, nil, &h, &d)
if err != nil { if err != nil {
return 0, false, err return 0, false, err
@ -174,7 +179,11 @@ func CreateKey(k Key, path string, access uint32) (newk Key, openedExisting bool
// DeleteKey deletes the subkey path of key k and its values. // DeleteKey deletes the subkey path of key k and its values.
func DeleteKey(k Key, path string) error { func DeleteKey(k Key, path string) error {
return regDeleteKey(syscall.Handle(k), syscall.StringToUTF16Ptr(path)) pathPointer, err := syscall.UTF16PtrFromString(path)
if err != nil {
return err
}
return regDeleteKey(syscall.Handle(k), pathPointer)
} }
// A KeyInfo describes the statistics of a key. It is returned by Stat. // A KeyInfo describes the statistics of a key. It is returned by Stat.

View File

@ -340,7 +340,11 @@ func (k Key) SetBinaryValue(name string, value []byte) error {
// DeleteValue removes a named value from the key k. // DeleteValue removes a named value from the key k.
func (k Key) DeleteValue(name string) error { func (k Key) DeleteValue(name string) error {
return regDeleteValue(syscall.Handle(k), syscall.StringToUTF16Ptr(name)) namePointer, err := syscall.UTF16PtrFromString(name)
if err != nil {
return err
}
return regDeleteValue(syscall.Handle(k), namePointer)
} }
// ReadValueNames returns the value names of key k. // ReadValueNames returns the value names of key k.

View File

@ -1074,6 +1074,7 @@ const (
IP_ADD_MEMBERSHIP = 0xc IP_ADD_MEMBERSHIP = 0xc
IP_DROP_MEMBERSHIP = 0xd IP_DROP_MEMBERSHIP = 0xd
IP_PKTINFO = 0x13 IP_PKTINFO = 0x13
IP_MTU_DISCOVER = 0x47
IPV6_V6ONLY = 0x1b IPV6_V6ONLY = 0x1b
IPV6_UNICAST_HOPS = 0x4 IPV6_UNICAST_HOPS = 0x4
@ -1083,6 +1084,7 @@ const (
IPV6_JOIN_GROUP = 0xc IPV6_JOIN_GROUP = 0xc
IPV6_LEAVE_GROUP = 0xd IPV6_LEAVE_GROUP = 0xd
IPV6_PKTINFO = 0x13 IPV6_PKTINFO = 0x13
IPV6_MTU_DISCOVER = 0x47
MSG_OOB = 0x1 MSG_OOB = 0x1
MSG_PEEK = 0x2 MSG_PEEK = 0x2
@ -1132,6 +1134,15 @@ const (
WSASYS_STATUS_LEN = 128 WSASYS_STATUS_LEN = 128
) )
// enum PMTUD_STATE from ws2ipdef.h
const (
IP_PMTUDISC_NOT_SET = 0
IP_PMTUDISC_DO = 1
IP_PMTUDISC_DONT = 2
IP_PMTUDISC_PROBE = 3
IP_PMTUDISC_MAX = 4
)
type WSABuf struct { type WSABuf struct {
Len uint32 Len uint32
Buf *byte Buf *byte
@ -1146,6 +1157,22 @@ type WSAMsg struct {
Flags uint32 Flags uint32
} }
type WSACMSGHDR struct {
Len uintptr
Level int32
Type int32
}
type IN_PKTINFO struct {
Addr [4]byte
Ifindex uint32
}
type IN6_PKTINFO struct {
Addr [16]byte
Ifindex uint32
}
// Flags for WSASocket // Flags for WSASocket
const ( const (
WSA_FLAG_OVERLAPPED = 0x01 WSA_FLAG_OVERLAPPED = 0x01

View File

@ -44,6 +44,8 @@ type Terminal struct {
// bytes, as an index into |line|). If it returns ok=false, the key // bytes, as an index into |line|). If it returns ok=false, the key
// press is processed normally. Otherwise it returns a replacement line // press is processed normally. Otherwise it returns a replacement line
// and the new cursor position. // and the new cursor position.
//
// This will be disabled during ReadPassword.
AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool) AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool)
// Escape contains a pointer to the escape codes for this terminal. // Escape contains a pointer to the escape codes for this terminal.
@ -692,6 +694,8 @@ func (t *Terminal) Write(buf []byte) (n int, err error) {
// ReadPassword temporarily changes the prompt and reads a password, without // ReadPassword temporarily changes the prompt and reads a password, without
// echo, from the terminal. // echo, from the terminal.
//
// The AutoCompleteCallback is disabled during this call.
func (t *Terminal) ReadPassword(prompt string) (line string, err error) { func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
t.lock.Lock() t.lock.Lock()
defer t.lock.Unlock() defer t.lock.Unlock()
@ -699,6 +703,11 @@ func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
oldPrompt := t.prompt oldPrompt := t.prompt
t.prompt = []rune(prompt) t.prompt = []rune(prompt)
t.echo = false t.echo = false
oldAutoCompleteCallback := t.AutoCompleteCallback
t.AutoCompleteCallback = nil
defer func() {
t.AutoCompleteCallback = oldAutoCompleteCallback
}()
line, err = t.readLine() line, err = t.readLine()

View File

@ -85,7 +85,7 @@ func (lim *Limiter) Burst() int {
// TokensAt returns the number of tokens available at time t. // TokensAt returns the number of tokens available at time t.
func (lim *Limiter) TokensAt(t time.Time) float64 { func (lim *Limiter) TokensAt(t time.Time) float64 {
lim.mu.Lock() lim.mu.Lock()
_, tokens := lim.advance(t) // does not mutate lim tokens := lim.advance(t) // does not mutate lim
lim.mu.Unlock() lim.mu.Unlock()
return tokens return tokens
} }
@ -99,8 +99,9 @@ func (lim *Limiter) Tokens() float64 {
// bursts of at most b tokens. // bursts of at most b tokens.
func NewLimiter(r Limit, b int) *Limiter { func NewLimiter(r Limit, b int) *Limiter {
return &Limiter{ return &Limiter{
limit: r, limit: r,
burst: b, burst: b,
tokens: float64(b),
} }
} }
@ -185,7 +186,7 @@ func (r *Reservation) CancelAt(t time.Time) {
return return
} }
// advance time to now // advance time to now
t, tokens := r.lim.advance(t) tokens := r.lim.advance(t)
// calculate new number of tokens // calculate new number of tokens
tokens += restoreTokens tokens += restoreTokens
if burst := float64(r.lim.burst); tokens > burst { if burst := float64(r.lim.burst); tokens > burst {
@ -306,7 +307,7 @@ func (lim *Limiter) SetLimitAt(t time.Time, newLimit Limit) {
lim.mu.Lock() lim.mu.Lock()
defer lim.mu.Unlock() defer lim.mu.Unlock()
t, tokens := lim.advance(t) tokens := lim.advance(t)
lim.last = t lim.last = t
lim.tokens = tokens lim.tokens = tokens
@ -323,7 +324,7 @@ func (lim *Limiter) SetBurstAt(t time.Time, newBurst int) {
lim.mu.Lock() lim.mu.Lock()
defer lim.mu.Unlock() defer lim.mu.Unlock()
t, tokens := lim.advance(t) tokens := lim.advance(t)
lim.last = t lim.last = t
lim.tokens = tokens lim.tokens = tokens
@ -344,21 +345,9 @@ func (lim *Limiter) reserveN(t time.Time, n int, maxFutureReserve time.Duration)
tokens: n, tokens: n,
timeToAct: t, timeToAct: t,
} }
} else if lim.limit == 0 {
var ok bool
if lim.burst >= n {
ok = true
lim.burst -= n
}
return Reservation{
ok: ok,
lim: lim,
tokens: lim.burst,
timeToAct: t,
}
} }
t, tokens := lim.advance(t) tokens := lim.advance(t)
// Calculate the remaining number of tokens resulting from the request. // Calculate the remaining number of tokens resulting from the request.
tokens -= float64(n) tokens -= float64(n)
@ -391,10 +380,11 @@ func (lim *Limiter) reserveN(t time.Time, n int, maxFutureReserve time.Duration)
return r return r
} }
// advance calculates and returns an updated state for lim resulting from the passage of time. // advance calculates and returns an updated number of tokens for lim
// resulting from the passage of time.
// lim is not changed. // lim is not changed.
// advance requires that lim.mu is held. // advance requires that lim.mu is held.
func (lim *Limiter) advance(t time.Time) (newT time.Time, newTokens float64) { func (lim *Limiter) advance(t time.Time) (newTokens float64) {
last := lim.last last := lim.last
if t.Before(last) { if t.Before(last) {
last = t last = t
@ -407,7 +397,7 @@ func (lim *Limiter) advance(t time.Time) (newT time.Time, newTokens float64) {
if burst := float64(lim.burst); tokens > burst { if burst := float64(lim.burst); tokens > burst {
tokens = burst tokens = burst
} }
return t, tokens return tokens
} }
// durationFromTokens is a unit conversion function from the number of tokens to the duration // durationFromTokens is a unit conversion function from the number of tokens to the duration
@ -416,8 +406,15 @@ func (limit Limit) durationFromTokens(tokens float64) time.Duration {
if limit <= 0 { if limit <= 0 {
return InfDuration return InfDuration
} }
seconds := tokens / float64(limit)
return time.Duration(float64(time.Second) * seconds) duration := (tokens / float64(limit)) * float64(time.Second)
// Cap the duration to the maximum representable int64 value, to avoid overflow.
if duration > float64(math.MaxInt64) {
return InfDuration
}
return time.Duration(duration)
} }
// tokensFromDuration is a unit conversion function from a time duration to the number of tokens // tokensFromDuration is a unit conversion function from a time duration to the number of tokens

25
vendor/modules.txt vendored
View File

@ -394,39 +394,40 @@ go.opentelemetry.io/proto/otlp/common/v1
go.opentelemetry.io/proto/otlp/metrics/v1 go.opentelemetry.io/proto/otlp/metrics/v1
go.opentelemetry.io/proto/otlp/resource/v1 go.opentelemetry.io/proto/otlp/resource/v1
go.opentelemetry.io/proto/otlp/trace/v1 go.opentelemetry.io/proto/otlp/trace/v1
# golang.org/x/crypto v0.35.0 # golang.org/x/crypto v0.37.0
## explicit; go 1.23.0 ## explicit; go 1.23.0
golang.org/x/crypto/ed25519 golang.org/x/crypto/ed25519
golang.org/x/crypto/pbkdf2 golang.org/x/crypto/pbkdf2
# golang.org/x/net v0.33.0 # golang.org/x/net v0.39.0
## explicit; go 1.18 ## explicit; go 1.23.0
golang.org/x/net/http/httpguts golang.org/x/net/http/httpguts
golang.org/x/net/http2 golang.org/x/net/http2
golang.org/x/net/http2/hpack golang.org/x/net/http2/hpack
golang.org/x/net/idna golang.org/x/net/idna
golang.org/x/net/internal/httpcommon
golang.org/x/net/internal/timeseries golang.org/x/net/internal/timeseries
golang.org/x/net/trace golang.org/x/net/trace
# golang.org/x/sync v0.11.0 # golang.org/x/sync v0.13.0
## explicit; go 1.18 ## explicit; go 1.23.0
golang.org/x/sync/errgroup golang.org/x/sync/errgroup
# golang.org/x/sys v0.31.0 # golang.org/x/sys v0.32.0
## explicit; go 1.23.0 ## explicit; go 1.23.0
golang.org/x/sys/plan9 golang.org/x/sys/plan9
golang.org/x/sys/unix golang.org/x/sys/unix
golang.org/x/sys/windows golang.org/x/sys/windows
golang.org/x/sys/windows/registry golang.org/x/sys/windows/registry
# golang.org/x/term v0.29.0 # golang.org/x/term v0.31.0
## explicit; go 1.18 ## explicit; go 1.23.0
golang.org/x/term golang.org/x/term
# golang.org/x/text v0.22.0 # golang.org/x/text v0.24.0
## explicit; go 1.18 ## explicit; go 1.23.0
golang.org/x/text/secure/bidirule golang.org/x/text/secure/bidirule
golang.org/x/text/transform golang.org/x/text/transform
golang.org/x/text/unicode/bidi golang.org/x/text/unicode/bidi
golang.org/x/text/unicode/norm golang.org/x/text/unicode/norm
golang.org/x/text/width golang.org/x/text/width
# golang.org/x/time v0.6.0 # golang.org/x/time v0.11.0
## explicit; go 1.18 ## explicit; go 1.23.0
golang.org/x/time/rate golang.org/x/time/rate
# google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 # google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38
## explicit; go 1.21 ## explicit; go 1.21