Update deps

quic-g0 0.57.1 fixes a panic when using Go 1.26
This commit is contained in:
Frank Denis
2025-11-26 12:12:19 +01:00
parent 280efc379a
commit 353e737098
53 changed files with 1674 additions and 849 deletions
+8 -8
View File
@@ -15,7 +15,7 @@ require (
github.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb
github.com/jedisct1/dlog v0.0.0-20241212093805-3c5fd791b405
github.com/jedisct1/go-clocksmith v0.0.0-20250224222044-e151f21a353a
github.com/jedisct1/go-dnsstamps v0.0.0-20240423203910-07a0735c7774
github.com/jedisct1/go-dnsstamps v0.0.0-20251112173516-191fc465df31
github.com/jedisct1/go-hpke-compact v0.0.0-20241212093903-5caa4621366f
github.com/jedisct1/go-ipcrypt v0.1.1
github.com/jedisct1/go-minisign v0.0.0-20241212093149-d2f9f49435c7
@@ -26,9 +26,9 @@ require (
github.com/lifenjoiner/dhcpdns v0.0.7
github.com/miekg/dns v1.1.68
github.com/powerman/check v1.9.0
github.com/quic-go/quic-go v0.56.0
golang.org/x/crypto v0.43.0
golang.org/x/net v0.46.0
github.com/quic-go/quic-go v0.57.1
golang.org/x/crypto v0.45.0
golang.org/x/net v0.47.0
golang.org/x/sys v0.38.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
)
@@ -40,12 +40,12 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/powerman/deepequal v0.1.0 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/smartystreets/goconvey v1.8.1 // indirect
golang.org/x/mod v0.29.0 // indirect
golang.org/x/mod v0.30.0 // indirect
golang.org/x/sync v0.18.0 // indirect
golang.org/x/text v0.30.0 // indirect
golang.org/x/tools v0.38.0 // indirect
golang.org/x/text v0.31.0 // indirect
golang.org/x/tools v0.39.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101 // indirect
google.golang.org/grpc v1.76.0 // indirect
google.golang.org/protobuf v1.36.10 // indirect
+18 -18
View File
@@ -33,8 +33,8 @@ github.com/jedisct1/dlog v0.0.0-20241212093805-3c5fd791b405 h1:6j/0utSiy3KhZSpFJ
github.com/jedisct1/dlog v0.0.0-20241212093805-3c5fd791b405/go.mod h1:OO1HpQNlMCMaPdHPuI00fhChZQZ8npbVTTjMvJUxUqQ=
github.com/jedisct1/go-clocksmith v0.0.0-20250224222044-e151f21a353a h1:8z8OvuZGZYGuvTeT5RD80ii6B6LftADl0EQr2z5asCg=
github.com/jedisct1/go-clocksmith v0.0.0-20250224222044-e151f21a353a/go.mod h1:SAINchklztk2jcLWJ4bpNF4KnwDUSUTX+cJbspWC2Rw=
github.com/jedisct1/go-dnsstamps v0.0.0-20240423203910-07a0735c7774 h1:DobL5d8UxrYzlD0PbU/EVBAGHuDiFyH46gr6povMw50=
github.com/jedisct1/go-dnsstamps v0.0.0-20240423203910-07a0735c7774/go.mod h1:mEGEFZsGe4sG5Mb3Xi89pmsy+TZ0946ArbYMGKAM5uA=
github.com/jedisct1/go-dnsstamps v0.0.0-20251112173516-191fc465df31 h1:O2qUxpVUeJxoBU5FJ0vGD03g5bY9uRrouaLlJeVOHr8=
github.com/jedisct1/go-dnsstamps v0.0.0-20251112173516-191fc465df31/go.mod h1:mEGEFZsGe4sG5Mb3Xi89pmsy+TZ0946ArbYMGKAM5uA=
github.com/jedisct1/go-hpke-compact v0.0.0-20241212093903-5caa4621366f h1:h5/HKrLaDfrb/Zi1y8eCsPGQpcOnKIslT/OpFc81i4c=
github.com/jedisct1/go-hpke-compact v0.0.0-20241212093903-5caa4621366f/go.mod h1:IjVYCPbDciyDZpJpUIYodX+FvctxGmnHVZ/ZwGBCjNA=
github.com/jedisct1/go-ipcrypt v0.1.1 h1:ZTcnCphIGyF5gePcq5x1+S/1JO1iavO2D3FSnIq5Zks=
@@ -63,35 +63,35 @@ github.com/powerman/check v1.9.0 h1:ppv0i78Gpd5P7phxfryPtSXZmUWiJxLyccusKWMG+Xk=
github.com/powerman/check v1.9.0/go.mod h1:i+FJaMwkYxByGnZ786ZBLiHMG78psGIQcV7UhCtwkUY=
github.com/powerman/deepequal v0.1.0 h1:sVwtyTsBuYIvdbLR1O2wzRY63YgPqdGZmk/o80l+C/U=
github.com/powerman/deepequal v0.1.0/go.mod h1:3k7aG/slufBhUANdN67o/UPg8i5YaiJ6FmibWX0cn04=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.56.0 h1:q/TW+OLismmXAehgFLczhCDTYB3bFmua4D9lsNBWxvY=
github.com/quic-go/quic-go v0.56.0/go.mod h1:9gx5KsFQtw2oZ6GZTyh+7YEvOxWCL9WZAepnHxgAo6c=
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
github.com/quic-go/quic-go v0.57.1 h1:25KAAR9QR8KZrCZRThWMKVAwGoiHIrNbT72ULHTuI10=
github.com/quic-go/quic-go v0.57.1/go.mod h1:ly4QBAjHA2VhdnxhojRsCUOeJwKYg+taDlos92xb1+s=
github.com/smarty/assertions v1.16.0 h1:EvHNkdRA4QHMrn75NZSoUQ/mAUXAYWfatfB01yTCzfY=
github.com/smarty/assertions v1.16.0/go.mod h1:duaaFdCS0K9dnoM50iyek/eYINOZ64gbh1Xlf6LG7AI=
github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190529164535-6a60838ec259/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101 h1:tRPGkdGHuewF4UisLzzHHr1spKw92qLM98nIzxbC0wY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
+380 -1
View File
@@ -13,6 +13,7 @@ import (
const (
DefaultPort = 443
DefaultDoTPort = 853
DefaultDNSPort = 53
StampScheme = "sdns://"
)
@@ -69,6 +70,7 @@ type ServerStamp struct {
Path string
Props ServerInformalProperties
Proto StampProtoType
BootstrapIPs []string
}
func NewDNSCryptServerStampFromLegacy(serverAddrStr string, serverPkStr string, providerName string, props ServerInformalProperties) (ServerStamp, error) {
@@ -108,6 +110,10 @@ func NewServerStampFromString(stampStr string) (ServerStamp, error) {
return newDNSCryptServerStamp(bin)
} else if bin[0] == uint8(StampProtoTypeDoH) {
return newDoHServerStamp(bin)
} else if bin[0] == uint8(StampProtoTypeTLS) {
return newDoTServerStamp(bin)
} else if bin[0] == uint8(StampProtoTypeDoQ) {
return newDoQServerStamp(bin)
} else if bin[0] == uint8(StampProtoTypeODoHTarget) {
return newODoHTargetStamp(bin)
} else if bin[0] == uint8(StampProtoTypeDNSCryptRelay) {
@@ -275,6 +281,9 @@ func newDoHServerStamp(bin []byte) (ServerStamp, error) {
}
pos++
if length > 0 {
if length != 32 {
return stamp, errors.New("Invalid stamp (certificate hash must be 32 bytes)")
}
stamp.Hashes = append(stamp.Hashes, bin[pos:pos+length])
}
pos += length
@@ -299,6 +308,29 @@ func newDoHServerStamp(bin []byte) (ServerStamp, error) {
stamp.Path = string(bin[pos : pos+length])
pos += length
// Parse optional bootstrap IP addresses (VLP format)
if pos < binLen {
for {
if pos >= binLen {
break
}
vlen := int(bin[pos])
length = vlen & ^0x80
if 1+length > binLen-pos {
return stamp, errors.New("Invalid stamp")
}
pos++
if length > 0 {
bootstrapIP := string(bin[pos : pos+length])
stamp.BootstrapIPs = append(stamp.BootstrapIPs, bootstrapIP)
}
pos += length
if vlen&0x80 != 0x80 {
break
}
}
}
if pos != binLen {
return stamp, errors.New("Invalid stamp (garbage after end)")
}
@@ -328,6 +360,202 @@ func newDoHServerStamp(bin []byte) (ServerStamp, error) {
return stamp, nil
}
// id(u8)=0x03 props addrLen(1) serverAddr hashLen(1) hash hostNameLen(1) hostName [ bootstrapLen(1) bootstrap ]
func newDoTServerStamp(bin []byte) (ServerStamp, error) {
stamp := ServerStamp{Proto: StampProtoTypeTLS}
if len(bin) < 13 {
return stamp, errors.New("Stamp is too short")
}
stamp.Props = ServerInformalProperties(binary.LittleEndian.Uint64(bin[1:9]))
binLen := len(bin)
pos := 9
length := int(bin[pos])
if 1+length >= binLen-pos {
return stamp, errors.New("Invalid stamp")
}
pos++
stamp.ServerAddrStr = string(bin[pos : pos+length])
pos += length
for {
vlen := int(bin[pos])
length = vlen & ^0x80
if 1+length >= binLen-pos {
return stamp, errors.New("Invalid stamp")
}
pos++
if length > 0 {
if length != 32 {
return stamp, errors.New("Invalid stamp (certificate hash must be 32 bytes)")
}
stamp.Hashes = append(stamp.Hashes, bin[pos:pos+length])
}
pos += length
if vlen&0x80 != 0x80 {
break
}
}
length = int(bin[pos])
if length >= binLen-pos {
return stamp, errors.New("Invalid stamp")
}
pos++
stamp.ProviderName = string(bin[pos : pos+length])
pos += length
// Parse optional bootstrap IP addresses (VLP format)
if pos < binLen {
for {
if pos >= binLen {
break
}
vlen := int(bin[pos])
length = vlen & ^0x80
if 1+length > binLen-pos {
return stamp, errors.New("Invalid stamp")
}
pos++
if length > 0 {
bootstrapIP := string(bin[pos : pos+length])
stamp.BootstrapIPs = append(stamp.BootstrapIPs, bootstrapIP)
}
pos += length
if vlen&0x80 != 0x80 {
break
}
}
}
if pos != binLen {
return stamp, errors.New("Invalid stamp (garbage after end)")
}
if len(stamp.ServerAddrStr) > 0 {
colIndex := strings.LastIndex(stamp.ServerAddrStr, ":")
bracketIndex := strings.LastIndex(stamp.ServerAddrStr, "]")
if colIndex < bracketIndex {
colIndex = -1
}
if colIndex < 0 {
colIndex = len(stamp.ServerAddrStr)
stamp.ServerAddrStr = fmt.Sprintf("%s:%d", stamp.ServerAddrStr, DefaultDoTPort)
}
if colIndex >= len(stamp.ServerAddrStr)-1 {
return stamp, errors.New("Invalid stamp (empty port)")
}
ipOnly := stamp.ServerAddrStr[:colIndex]
if err := validatePort(stamp.ServerAddrStr[colIndex+1:]); err != nil {
return stamp, errors.New("Invalid stamp (port range)")
}
if ipOnly != "" && net.ParseIP(strings.TrimRight(strings.TrimLeft(ipOnly, "["), "]")) == nil {
return stamp, errors.New("Invalid stamp (IP address)")
}
}
return stamp, nil
}
// id(u8)=0x04 props addrLen(1) serverAddr hashLen(1) hash hostNameLen(1) hostName [ bootstrapLen(1) bootstrap ]
func newDoQServerStamp(bin []byte) (ServerStamp, error) {
stamp := ServerStamp{Proto: StampProtoTypeDoQ}
if len(bin) < 13 {
return stamp, errors.New("Stamp is too short")
}
stamp.Props = ServerInformalProperties(binary.LittleEndian.Uint64(bin[1:9]))
binLen := len(bin)
pos := 9
length := int(bin[pos])
if 1+length >= binLen-pos {
return stamp, errors.New("Invalid stamp")
}
pos++
stamp.ServerAddrStr = string(bin[pos : pos+length])
pos += length
for {
vlen := int(bin[pos])
length = vlen & ^0x80
if 1+length >= binLen-pos {
return stamp, errors.New("Invalid stamp")
}
pos++
if length > 0 {
if length != 32 {
return stamp, errors.New("Invalid stamp (certificate hash must be 32 bytes)")
}
stamp.Hashes = append(stamp.Hashes, bin[pos:pos+length])
}
pos += length
if vlen&0x80 != 0x80 {
break
}
}
length = int(bin[pos])
if length >= binLen-pos {
return stamp, errors.New("Invalid stamp")
}
pos++
stamp.ProviderName = string(bin[pos : pos+length])
pos += length
// Parse optional bootstrap IP addresses (VLP format)
if pos < binLen {
for {
if pos >= binLen {
break
}
vlen := int(bin[pos])
length = vlen & ^0x80
if 1+length > binLen-pos {
return stamp, errors.New("Invalid stamp")
}
pos++
if length > 0 {
bootstrapIP := string(bin[pos : pos+length])
stamp.BootstrapIPs = append(stamp.BootstrapIPs, bootstrapIP)
}
pos += length
if vlen&0x80 != 0x80 {
break
}
}
}
if pos != binLen {
return stamp, errors.New("Invalid stamp (garbage after end)")
}
if len(stamp.ServerAddrStr) > 0 {
colIndex := strings.LastIndex(stamp.ServerAddrStr, ":")
bracketIndex := strings.LastIndex(stamp.ServerAddrStr, "]")
if colIndex < bracketIndex {
colIndex = -1
}
if colIndex < 0 {
colIndex = len(stamp.ServerAddrStr)
stamp.ServerAddrStr = fmt.Sprintf("%s:%d", stamp.ServerAddrStr, DefaultDoTPort)
}
if colIndex >= len(stamp.ServerAddrStr)-1 {
return stamp, errors.New("Invalid stamp (empty port)")
}
ipOnly := stamp.ServerAddrStr[:colIndex]
if err := validatePort(stamp.ServerAddrStr[colIndex+1:]); err != nil {
return stamp, errors.New("Invalid stamp (port range)")
}
if ipOnly != "" && net.ParseIP(strings.TrimRight(strings.TrimLeft(ipOnly, "["), "]")) == nil {
return stamp, errors.New("Invalid stamp (IP address)")
}
}
return stamp, nil
}
// id(u8)=0x05 props hostNameLen(1) hostName pathLen(1) path
func newODoHTargetStamp(bin []byte) (ServerStamp, error) {
@@ -431,6 +659,9 @@ func newODoHRelayStamp(bin []byte) (ServerStamp, error) {
}
pos++
if length > 0 {
if length != 32 {
return stamp, errors.New("Invalid stamp (certificate hash must be 32 bytes)")
}
stamp.Hashes = append(stamp.Hashes, bin[pos:pos+length])
}
pos += length
@@ -455,6 +686,29 @@ func newODoHRelayStamp(bin []byte) (ServerStamp, error) {
stamp.Path = string(bin[pos : pos+length])
pos += length
// Parse optional bootstrap IP addresses (VLP format)
if pos < binLen {
for {
if pos >= binLen {
break
}
vlen := int(bin[pos])
length = vlen & ^0x80
if 1+length > binLen-pos {
return stamp, errors.New("Invalid stamp")
}
pos++
if length > 0 {
bootstrapIP := string(bin[pos : pos+length])
stamp.BootstrapIPs = append(stamp.BootstrapIPs, bootstrapIP)
}
pos += length
if vlen&0x80 != 0x80 {
break
}
}
}
if pos != binLen {
return stamp, errors.New("Invalid stamp (garbage after end)")
}
@@ -485,7 +739,8 @@ func newODoHRelayStamp(bin []byte) (ServerStamp, error) {
}
func validatePort(port string) error {
if _, err := strconv.ParseUint(port, 10, 16); err != nil {
p, err := strconv.ParseUint(port, 10, 16)
if err != nil || p == 0 {
return errors.New("Invalid port")
}
return nil
@@ -498,6 +753,10 @@ func (stamp *ServerStamp) String() string {
return stamp.dnsCryptString()
} else if stamp.Proto == StampProtoTypeDoH {
return stamp.dohString()
} else if stamp.Proto == StampProtoTypeTLS {
return stamp.dotString()
} else if stamp.Proto == StampProtoTypeDoQ {
return stamp.doqString()
} else if stamp.Proto == StampProtoTypeODoHTarget {
return stamp.oDohTargetString()
} else if stamp.Proto == StampProtoTypeDNSCryptRelay {
@@ -579,6 +838,113 @@ func (stamp *ServerStamp) dohString() string {
bin = append(bin, uint8(len(stamp.Path)))
bin = append(bin, []uint8(stamp.Path)...)
// Serialize optional bootstrap IP addresses (VLP format)
if len(stamp.BootstrapIPs) > 0 {
last := len(stamp.BootstrapIPs) - 1
for i, bootstrapIP := range stamp.BootstrapIPs {
vlen := len(bootstrapIP)
if i < last {
vlen |= 0x80
}
bin = append(bin, uint8(vlen))
bin = append(bin, []uint8(bootstrapIP)...)
}
}
str := base64.RawURLEncoding.EncodeToString(bin)
return StampScheme + str
}
func (stamp *ServerStamp) dotString() string {
bin := make([]uint8, 9)
bin[0] = uint8(StampProtoTypeTLS)
binary.LittleEndian.PutUint64(bin[1:9], uint64(stamp.Props))
serverAddrStr := stamp.ServerAddrStr
if strings.HasSuffix(serverAddrStr, ":"+strconv.Itoa(DefaultDoTPort)) {
serverAddrStr = serverAddrStr[:len(serverAddrStr)-1-len(strconv.Itoa(DefaultDoTPort))]
}
bin = append(bin, uint8(len(serverAddrStr)))
bin = append(bin, []uint8(serverAddrStr)...)
if len(stamp.Hashes) == 0 {
bin = append(bin, uint8(0))
} else {
last := len(stamp.Hashes) - 1
for i, hash := range stamp.Hashes {
vlen := len(hash)
if i < last {
vlen |= 0x80
}
bin = append(bin, uint8(vlen))
bin = append(bin, hash...)
}
}
bin = append(bin, uint8(len(stamp.ProviderName)))
bin = append(bin, []uint8(stamp.ProviderName)...)
// Serialize optional bootstrap IP addresses (VLP format)
if len(stamp.BootstrapIPs) > 0 {
last := len(stamp.BootstrapIPs) - 1
for i, bootstrapIP := range stamp.BootstrapIPs {
vlen := len(bootstrapIP)
if i < last {
vlen |= 0x80
}
bin = append(bin, uint8(vlen))
bin = append(bin, []uint8(bootstrapIP)...)
}
}
str := base64.RawURLEncoding.EncodeToString(bin)
return StampScheme + str
}
func (stamp *ServerStamp) doqString() string {
bin := make([]uint8, 9)
bin[0] = uint8(StampProtoTypeDoQ)
binary.LittleEndian.PutUint64(bin[1:9], uint64(stamp.Props))
serverAddrStr := stamp.ServerAddrStr
if strings.HasSuffix(serverAddrStr, ":"+strconv.Itoa(DefaultDoTPort)) {
serverAddrStr = serverAddrStr[:len(serverAddrStr)-1-len(strconv.Itoa(DefaultDoTPort))]
}
bin = append(bin, uint8(len(serverAddrStr)))
bin = append(bin, []uint8(serverAddrStr)...)
if len(stamp.Hashes) == 0 {
bin = append(bin, uint8(0))
} else {
last := len(stamp.Hashes) - 1
for i, hash := range stamp.Hashes {
vlen := len(hash)
if i < last {
vlen |= 0x80
}
bin = append(bin, uint8(vlen))
bin = append(bin, hash...)
}
}
bin = append(bin, uint8(len(stamp.ProviderName)))
bin = append(bin, []uint8(stamp.ProviderName)...)
// Serialize optional bootstrap IP addresses (VLP format)
if len(stamp.BootstrapIPs) > 0 {
last := len(stamp.BootstrapIPs) - 1
for i, bootstrapIP := range stamp.BootstrapIPs {
vlen := len(bootstrapIP)
if i < last {
vlen |= 0x80
}
bin = append(bin, uint8(vlen))
bin = append(bin, []uint8(bootstrapIP)...)
}
}
str := base64.RawURLEncoding.EncodeToString(bin)
return StampScheme + str
@@ -648,6 +1014,19 @@ func (stamp *ServerStamp) oDohRelayString() string {
bin = append(bin, uint8(len(stamp.Path)))
bin = append(bin, []uint8(stamp.Path)...)
// Serialize optional bootstrap IP addresses (VLP format)
if len(stamp.BootstrapIPs) > 0 {
last := len(stamp.BootstrapIPs) - 1
for i, bootstrapIP := range stamp.BootstrapIPs {
vlen := len(bootstrapIP)
if i < last {
vlen |= 0x80
}
bin = append(bin, uint8(vlen))
bin = append(bin, []uint8(bootstrapIP)...)
}
}
str := base64.RawURLEncoding.EncodeToString(bin)
return StampScheme + str
+2 -2
View File
@@ -1,3 +1,3 @@
[submodule "integrationtests/interop/qifs"]
path = integrationtests/interop/qifs
[submodule "interop/qifs"]
path = interop/qifs
url = https://github.com/qpackers/qifs.git
+9 -10
View File
@@ -1,23 +1,22 @@
run:
linters-settings:
version: "2"
linters:
disable-all: true
default: none
enable:
- asciicheck
- copyloopvar
- exhaustive
- goconst
- gofmt # redundant, since gofmt *should* be a no-op after gofumpt
- gofumpt
- goimports
- gosimple
- govet
- ineffassign
- misspell
- nolintlint
- prealloc
- staticcheck
- stylecheck
- unconvert
- unparam
- unused
- usetesting
formatters:
enable:
- gofmt
- gofumpt
- goimports
+3 -3
View File
@@ -4,9 +4,9 @@
[![Code Coverage](https://img.shields.io/codecov/c/github/quic-go/qpack/master.svg?style=flat-square)](https://codecov.io/gh/quic-go/qpack)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/quic-go.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:quic-go)
This is a minimal QPACK ([RFC 9204](https://datatracker.ietf.org/doc/html/rfc9204)) implementation in Go. It is minimal in the sense that it doesn't use the dynamic table at all, but just the static table and (Huffman encoded) string literals. Wherever possible, it reuses code from the [HPACK implementation in the Go standard library](https://github.com/golang/net/tree/master/http2/hpack).
This is a minimal QPACK ([RFC 9204](https://datatracker.ietf.org/doc/html/rfc9204)) implementation in Go. It reuses the Huffman encoder / decoder code from the [HPACK implementation in the Go standard library](https://github.com/golang/net/tree/master/http2/hpack).
It is interoperable with other QPACK implementations (both encoders and decoders), however it won't achieve a high compression efficiency. If you're interested in dynamic table support, please comment on [the issue](https://github.com/quic-go/qpack/issues/33).
It is fully interoperable with other QPACK implementations (both encoders and decoders). However, it does not support the dynamic table and relies solely on the static table and string literals (including Huffman encoding), which limits compression efficiency. If you're interested in dynamic table support, please comment on [issue #33](https://github.com/quic-go/qpack/issues/33).
## Running the Interop Tests
@@ -17,5 +17,5 @@ git submodule update --init --recursive
Then run the tests:
```bash
go test -v ./integrationtests/interop/
go test -v ./interop
```
+84 -176
View File
@@ -1,248 +1,157 @@
package qpack
import (
"bytes"
"errors"
"fmt"
"sync"
"io"
"golang.org/x/net/http2/hpack"
)
// A decodingError is something the spec defines as a decoding error.
type decodingError struct {
err error
}
func (de decodingError) Error() string {
return fmt.Sprintf("decoding error: %v", de.err)
}
// An invalidIndexError is returned when an encoder references a table
// entry before the static table or after the end of the dynamic table.
// An invalidIndexError is returned when decoding encounters an invalid index
// (e.g., an index that is out of bounds for the static table).
type invalidIndexError int
func (e invalidIndexError) Error() string {
return fmt.Sprintf("invalid indexed representation index %d", int(e))
}
var errNoDynamicTable = decodingError{errors.New("no dynamic table")}
var errNoDynamicTable = errors.New("no dynamic table")
// errNeedMore is an internal sentinel error value that means the
// buffer is truncated and we need to read more data before we can
// continue parsing.
var errNeedMore = errors.New("need more data")
// A Decoder decodes QPACK header blocks.
// A Decoder can be reused to decode multiple header blocks on different streams
// on the same connection (e.g., headers then trailers).
// This will be useful when dynamic table support is added.
type Decoder struct{}
// A Decoder is the decoding context for incremental processing of
// header blocks.
type Decoder struct {
mutex sync.Mutex
// DecodeFunc is a function that decodes the next header field from a header block.
// It should be called repeatedly until it returns io.EOF.
// It returns io.EOF when all header fields have been decoded.
// Any error other than io.EOF indicates a decoding error.
type DecodeFunc func() (HeaderField, error)
emitFunc func(f HeaderField)
readRequiredInsertCount bool
readDeltaBase bool
// buf is the unparsed buffer. It's only written to
// saveBuf if it was truncated in the middle of a header
// block. Because it's usually not owned, we can only
// process it under Write.
buf []byte // not owned; only valid during Write
// saveBuf is previous data passed to Write which we weren't able
// to fully parse before. Unlike buf, we own this data.
saveBuf bytes.Buffer
// NewDecoder returns a new Decoder.
func NewDecoder() *Decoder {
return &Decoder{}
}
// NewDecoder returns a new decoder
// The emitFunc will be called for each valid field parsed,
// in the same goroutine as calls to Write, before Write returns.
func NewDecoder(emitFunc func(f HeaderField)) *Decoder {
return &Decoder{emitFunc: emitFunc}
}
// Decode returns a function that decodes header fields from the given header block.
// It does not copy the slice; the caller must ensure it remains valid during decoding.
func (d *Decoder) Decode(p []byte) DecodeFunc {
var readRequiredInsertCount bool
var readDeltaBase bool
func (d *Decoder) Write(p []byte) (int, error) {
if len(p) == 0 {
return 0, nil
}
d.mutex.Lock()
n, err := d.writeLocked(p)
d.mutex.Unlock()
return n, err
}
func (d *Decoder) writeLocked(p []byte) (int, error) {
// Only copy the data if we have to. Optimistically assume
// that p will contain a complete header block.
if d.saveBuf.Len() == 0 {
d.buf = p
} else {
d.saveBuf.Write(p)
d.buf = d.saveBuf.Bytes()
d.saveBuf.Reset()
}
if err := d.decode(); err != nil {
if err != errNeedMore {
return 0, err
return func() (HeaderField, error) {
if !readRequiredInsertCount {
requiredInsertCount, rest, err := readVarInt(8, p)
if err != nil {
return HeaderField{}, err
}
p = rest
readRequiredInsertCount = true
if requiredInsertCount != 0 {
return HeaderField{}, errors.New("expected Required Insert Count to be zero")
}
}
// TODO: limit the size of the buffer
d.saveBuf.Write(d.buf)
}
return len(p), nil
}
// DecodeFull decodes an entire block.
func (d *Decoder) DecodeFull(p []byte) ([]HeaderField, error) {
if len(p) == 0 {
return []HeaderField{}, nil
}
d.mutex.Lock()
defer d.mutex.Unlock()
saveFunc := d.emitFunc
defer func() { d.emitFunc = saveFunc }()
var hf []HeaderField
d.emitFunc = func(f HeaderField) { hf = append(hf, f) }
if _, err := d.writeLocked(p); err != nil {
return nil, err
}
if err := d.Close(); err != nil {
return nil, err
}
return hf, nil
}
// Close declares that the decoding is complete and resets the Decoder
// to be reused again for a new header block. If there is any remaining
// data in the decoder's buffer, Close returns an error.
func (d *Decoder) Close() error {
if d.saveBuf.Len() > 0 {
d.saveBuf.Reset()
return decodingError{errors.New("truncated headers")}
}
d.readRequiredInsertCount = false
d.readDeltaBase = false
return nil
}
func (d *Decoder) decode() error {
if !d.readRequiredInsertCount {
requiredInsertCount, rest, err := readVarInt(8, d.buf)
if err != nil {
return err
if !readDeltaBase {
base, rest, err := readVarInt(7, p)
if err != nil {
return HeaderField{}, err
}
p = rest
readDeltaBase = true
if base != 0 {
return HeaderField{}, errors.New("expected Base to be zero")
}
}
d.readRequiredInsertCount = true
if requiredInsertCount != 0 {
return decodingError{errors.New("expected Required Insert Count to be zero")}
}
d.buf = rest
}
if !d.readDeltaBase {
base, rest, err := readVarInt(7, d.buf)
if err != nil {
return err
}
d.readDeltaBase = true
if base != 0 {
return decodingError{errors.New("expected Base to be zero")}
}
d.buf = rest
}
if len(d.buf) == 0 {
return errNeedMore
}
for len(d.buf) > 0 {
b := d.buf[0]
if len(p) == 0 {
return HeaderField{}, io.EOF
}
b := p[0]
var hf HeaderField
var rest []byte
var err error
switch {
case b&0x80 > 0: // 1xxxxxxx
err = d.parseIndexedHeaderField()
case b&0xc0 == 0x40: // 01xxxxxx
err = d.parseLiteralHeaderField()
case b&0xe0 == 0x20: // 001xxxxx
err = d.parseLiteralHeaderFieldWithoutNameReference()
case (b & 0x80) > 0: // 1xxxxxxx
hf, rest, err = d.parseIndexedHeaderField(p)
case (b & 0xc0) == 0x40: // 01xxxxxx
hf, rest, err = d.parseLiteralHeaderField(p)
case (b & 0xe0) == 0x20: // 001xxxxx
hf, rest, err = d.parseLiteralHeaderFieldWithoutNameReference(p)
default:
err = fmt.Errorf("unexpected type byte: %#x", b)
}
p = rest
if err != nil {
return err
return HeaderField{}, err
}
return hf, nil
}
return nil
}
func (d *Decoder) parseIndexedHeaderField() error {
buf := d.buf
func (d *Decoder) parseIndexedHeaderField(buf []byte) (_ HeaderField, rest []byte, _ error) {
if buf[0]&0x40 == 0 {
return errNoDynamicTable
return HeaderField{}, buf, errNoDynamicTable
}
index, buf, err := readVarInt(6, buf)
index, rest, err := readVarInt(6, buf)
if err != nil {
return err
return HeaderField{}, buf, err
}
hf, ok := d.at(index)
if !ok {
return decodingError{invalidIndexError(index)}
return HeaderField{}, buf, invalidIndexError(index)
}
d.emitFunc(hf)
d.buf = buf
return nil
return hf, rest, nil
}
func (d *Decoder) parseLiteralHeaderField() error {
buf := d.buf
func (d *Decoder) parseLiteralHeaderField(buf []byte) (_ HeaderField, rest []byte, _ error) {
if buf[0]&0x10 == 0 {
return errNoDynamicTable
return HeaderField{}, buf, errNoDynamicTable
}
// We don't need to check the value of the N-bit here.
// It's only relevant when re-encoding header fields,
// and determines whether the header field can be added to the dynamic table.
// Since we don't support the dynamic table, we can ignore it.
index, buf, err := readVarInt(4, buf)
index, rest, err := readVarInt(4, buf)
if err != nil {
return err
return HeaderField{}, buf, err
}
hf, ok := d.at(index)
if !ok {
return decodingError{invalidIndexError(index)}
return HeaderField{}, buf, invalidIndexError(index)
}
buf = rest
if len(buf) == 0 {
return errNeedMore
return HeaderField{}, buf, io.ErrUnexpectedEOF
}
usesHuffman := buf[0]&0x80 > 0
val, buf, err := d.readString(buf, 7, usesHuffman)
val, rest, err := d.readString(rest, 7, usesHuffman)
if err != nil {
return err
return HeaderField{}, rest, err
}
hf.Value = val
d.emitFunc(hf)
d.buf = buf
return nil
return hf, rest, nil
}
func (d *Decoder) parseLiteralHeaderFieldWithoutNameReference() error {
buf := d.buf
func (d *Decoder) parseLiteralHeaderFieldWithoutNameReference(buf []byte) (_ HeaderField, rest []byte, _ error) {
usesHuffmanForName := buf[0]&0x8 > 0
name, buf, err := d.readString(buf, 3, usesHuffmanForName)
name, rest, err := d.readString(buf, 3, usesHuffmanForName)
if err != nil {
return err
return HeaderField{}, rest, err
}
buf = rest
if len(buf) == 0 {
return errNeedMore
return HeaderField{}, rest, io.ErrUnexpectedEOF
}
usesHuffmanForVal := buf[0]&0x80 > 0
val, buf, err := d.readString(buf, 7, usesHuffmanForVal)
val, rest, err := d.readString(buf, 7, usesHuffmanForVal)
if err != nil {
return err
return HeaderField{}, rest, err
}
d.emitFunc(HeaderField{Name: name, Value: val})
d.buf = buf
return nil
return HeaderField{Name: name, Value: val}, rest, nil
}
func (d *Decoder) readString(buf []byte, n uint8, usesHuffman bool) (string, []byte, error) {
@@ -251,11 +160,10 @@ func (d *Decoder) readString(buf []byte, n uint8, usesHuffman bool) (string, []b
return "", nil, err
}
if uint64(len(buf)) < l {
return "", nil, errNeedMore
return "", nil, io.ErrUnexpectedEOF
}
var val string
if usesHuffman {
var err error
val, err = hpack.HuffmanDecodeToString(buf[:l])
if err != nil {
return "", nil, err
+1 -1
View File
@@ -105,7 +105,7 @@ var staticTableEntries = [...]HeaderField{
// Only needed for tests.
// use go:linkname to retrieve the static table.
//
//nolint:deadcode,unused
//nolint:unused
func getStaticTable() []HeaderField {
return staticTableEntries[:]
}
+7 -4
View File
@@ -2,7 +2,10 @@ package qpack
// copied from the Go standard library HPACK implementation
import "errors"
import (
"errors"
"io"
)
var errVarintOverflow = errors.New("varint integer overflow")
@@ -31,13 +34,13 @@ func appendVarInt(dst []byte, n byte, i uint64) []byte {
// n must always be between 1 and 8.
//
// The returned remain buffer is either a smaller suffix of p, or err != nil.
// The error is errNeedMore if p doesn't contain a complete integer.
// The error is io.ErrUnexpectedEOF if p doesn't contain a complete integer.
func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) {
if n < 1 || n > 8 {
panic("bad n")
}
if len(p) == 0 {
return 0, p, errNeedMore
return 0, p, io.ErrUnexpectedEOF
}
i = uint64(p[0])
if n < 8 {
@@ -62,5 +65,5 @@ func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) {
return 0, origP, errVarintOverflow
}
}
return 0, origP, errNeedMore
return 0, origP, io.ErrUnexpectedEOF
}
+1
View File
@@ -34,6 +34,7 @@ Detailed documentation can be found on [quic-go.net](https://quic-go.net/docs/).
| [gost](https://github.com/go-gost/gost) | A simple security tunnel written in Go | ![GitHub Repo stars](https://img.shields.io/github/stars/go-gost/gost?style=flat-square) |
| [Hysteria](https://github.com/apernet/hysteria) | A powerful, lightning fast and censorship resistant proxy | ![GitHub Repo stars](https://img.shields.io/github/stars/apernet/hysteria?style=flat-square) |
| [Mercure](https://github.com/dunglas/mercure) | An open, easy, fast, reliable and battery-efficient solution for real-time communications | ![GitHub Repo stars](https://img.shields.io/github/stars/dunglas/mercure?style=flat-square) |
| [nodepass](https://github.com/yosebyte/nodepass) | A secure, efficient TCP/UDP tunneling solution that delivers fast, reliable access across network restrictions using pre-established TCP/QUIC connections | ![GitHub Repo stars](https://img.shields.io/github/stars/yosebyte/nodepass?style=flat-square) |
| [OONI Probe](https://github.com/ooni/probe-cli) | Next generation OONI Probe. Library and CLI tool. | ![GitHub Repo stars](https://img.shields.io/github/stars/ooni/probe-cli?style=flat-square) |
| [reverst](https://github.com/flipt-io/reverst) | Reverse Tunnels in Go over HTTP/3 and QUIC | ![GitHub Repo stars](https://img.shields.io/github/stars/flipt-io/reverst?style=flat-square) |
| [RoadRunner](https://github.com/roadrunner-server/roadrunner) | High-performance PHP application server, process manager written in Go and powered with plugins | ![GitHub Repo stars](https://img.shields.io/github/stars/roadrunner-server/roadrunner?style=flat-square) |
-7
View File
@@ -157,13 +157,6 @@ func (m *connIDGenerator) SetHandshakeComplete(connIDExpiry monotime.Time) {
}
}
func (m *connIDGenerator) NextRetireTime() monotime.Time {
if len(m.connIDsToRetire) == 0 {
return 0
}
return m.connIDsToRetire[0].t
}
func (m *connIDGenerator) RemoveRetiredConnIDs(now monotime.Time) {
if len(m.connIDsToRetire) == 0 {
return
+7 -3
View File
@@ -885,9 +885,6 @@ func (c *Conn) maybeResetTimer() {
return
}
if t := c.connIDGenerator.NextRetireTime(); !t.IsZero() && t.Before(deadline) {
deadline = t
}
if !c.pacingDeadline.IsZero() && c.pacingDeadline.Before(deadline) {
deadline = c.pacingDeadline
}
@@ -3082,6 +3079,13 @@ func (c *Conn) QlogTrace() qlogwriter.Trace {
return c.qlogTrace
}
// NextConnection transitions a connection to be usable after a 0-RTT rejection.
// It waits for the handshake to complete and then enables the connection for normal use.
// This should be called when the server rejects 0-RTT and the application receives
// [Err0RTTRejected] errors.
//
// Note that 0-RTT rejection invalidates all data sent in 0-RTT packets. It is the
// application's responsibility to handle this (for example by resending the data).
func (c *Conn) NextConnection(ctx context.Context) (*Conn, error) {
// The handshake might fail after the server rejected 0-RTT.
// This could happen if the Finished message is malformed or never received.
+38 -27
View File
@@ -59,7 +59,7 @@ type ClientConn struct {
// maxResponseHeaderBytes specifies a limit on how many response bytes are
// allowed in the server's response header.
maxResponseHeaderBytes uint64
maxResponseHeaderBytes int
// disableCompression, if true, prevents the Transport from requesting compression with an
// "Accept-Encoding: gzip" request header when the Request contains no existing Accept-Encoding value.
@@ -82,7 +82,7 @@ func newClientConn(
additionalSettings map[uint64]uint64,
streamHijacker func(FrameType, quic.ConnectionTracingID, *quic.Stream, error) (hijacked bool, err error),
uniStreamHijacker func(StreamType, quic.ConnectionTracingID, *quic.ReceiveStream, error) (hijacked bool),
maxResponseHeaderBytes int64,
maxResponseHeaderBytes int,
disableCompression bool,
logger *slog.Logger,
) *ClientConn {
@@ -95,9 +95,9 @@ func newClientConn(
if maxResponseHeaderBytes <= 0 {
c.maxResponseHeaderBytes = defaultMaxResponseHeaderBytes
} else {
c.maxResponseHeaderBytes = uint64(maxResponseHeaderBytes)
c.maxResponseHeaderBytes = maxResponseHeaderBytes
}
c.decoder = qpack.NewDecoder(func(hf qpack.HeaderField) {})
c.decoder = qpack.NewDecoder()
c.requestWriter = newRequestWriter()
c.conn = newConnection(
conn.Context(),
@@ -137,10 +137,15 @@ func (c *ClientConn) setupConn() error {
b := make([]byte, 0, 64)
b = quicvarint.Append(b, streamTypeControlStream)
// send the SETTINGS frame
b = (&settingsFrame{Datagram: c.enableDatagrams, Other: c.additionalSettings}).Append(b)
b = (&settingsFrame{
Datagram: c.enableDatagrams,
Other: c.additionalSettings,
MaxFieldSectionSize: int64(c.maxResponseHeaderBytes),
}).Append(b)
if c.conn.qlogger != nil {
sf := qlog.SettingsFrame{
Other: maps.Clone(c.additionalSettings),
MaxFieldSectionSize: int64(c.maxResponseHeaderBytes),
Other: maps.Clone(c.additionalSettings),
}
if c.enableDatagrams {
sf.Datagram = pointer(true)
@@ -332,31 +337,37 @@ func (c *ClientConn) sendRequestBody(str *RequestStream, body io.ReadCloser, con
func (c *ClientConn) doRequest(req *http.Request, str *RequestStream) (*http.Response, error) {
trace := httptrace.ContextClientTrace(req.Context())
var sendingReqFailed bool
if err := str.sendRequestHeader(req); err != nil {
traceWroteRequest(trace, err)
return nil, err
if c.logger != nil {
c.logger.Debug("error writing request", "error", err)
}
sendingReqFailed = true
}
if req.Body == nil {
traceWroteRequest(trace, nil)
str.Close()
} else {
// send the request body asynchronously
go func() {
contentLength := int64(-1)
// According to the documentation for http.Request.ContentLength,
// a value of 0 with a non-nil Body is also treated as unknown content length.
if req.ContentLength > 0 {
contentLength = req.ContentLength
}
err := c.sendRequestBody(str, req.Body, contentLength)
traceWroteRequest(trace, err)
if err != nil {
if c.logger != nil {
c.logger.Debug("error writing request", "error", err)
}
}
if !sendingReqFailed {
if req.Body == nil {
traceWroteRequest(trace, nil)
str.Close()
}()
} else {
// send the request body asynchronously
go func() {
contentLength := int64(-1)
// According to the documentation for http.Request.ContentLength,
// a value of 0 with a non-nil Body is also treated as unknown content length.
if req.ContentLength > 0 {
contentLength = req.ContentLength
}
err := c.sendRequestBody(str, req.Body, contentLength)
traceWroteRequest(trace, err)
if err != nil {
if c.logger != nil {
c.logger.Debug("error writing request", "error", err)
}
}
str.Close()
}()
}
}
// copy from net/http: support 1xx responses
+12 -7
View File
@@ -76,7 +76,7 @@ func newConnection(
logger: logger,
idleTimeout: idleTimeout,
enableDatagrams: enableDatagrams,
decoder: qpack.NewDecoder(func(hf qpack.HeaderField) {}),
decoder: qpack.NewDecoder(),
receivedSettings: make(chan struct{}),
streams: make(map[quic.StreamID]*stateTrackingStream),
maxStreamID: invalidStreamID,
@@ -147,7 +147,7 @@ func (c *Conn) openRequestStream(
requestWriter *requestWriter,
reqDone chan<- struct{},
disableCompression bool,
maxHeaderBytes uint64,
maxHeaderBytes int,
) (*RequestStream, error) {
c.streamMx.Lock()
maxStreamID := c.maxStreamID
@@ -193,17 +193,22 @@ func (c *Conn) openRequestStream(
), nil
}
func (c *Conn) decodeTrailers(r io.Reader, streamID quic.StreamID, hf *headersFrame, maxHeaderBytes uint64) (http.Header, error) {
if hf.Length > maxHeaderBytes {
func (c *Conn) decodeTrailers(r io.Reader, streamID quic.StreamID, hf *headersFrame, maxHeaderBytes int) (http.Header, error) {
if hf.Length > uint64(maxHeaderBytes) {
maybeQlogInvalidHeadersFrame(c.qlogger, streamID, hf.Length)
return nil, fmt.Errorf("HEADERS frame too large: %d bytes (max: %d)", hf.Length, maxHeaderBytes)
return nil, fmt.Errorf("http3: HEADERS frame too large: %d bytes (max: %d)", hf.Length, maxHeaderBytes)
}
b := make([]byte, hf.Length)
if _, err := io.ReadFull(r, b); err != nil {
return nil, err
}
fields, err := c.decoder.DecodeFull(b)
decodeFn := c.decoder.Decode(b)
var fields []qpack.HeaderField
if c.qlogger != nil {
fields = make([]qpack.HeaderField, 0, 16)
}
trailers, err := parseTrailers(decodeFn, &fields)
if err != nil {
maybeQlogInvalidHeadersFrame(c.qlogger, streamID, hf.Length)
return nil, err
@@ -211,7 +216,7 @@ func (c *Conn) decodeTrailers(r io.Reader, streamID quic.StreamID, hf *headersFr
if c.qlogger != nil {
qlogParsedHeadersFrame(c.qlogger, streamID, hf, fields)
}
return parseTrailers(fields)
return trailers, nil
}
// only used by the server
+21 -18
View File
@@ -9,24 +9,25 @@ import (
type ErrCode quic.ApplicationErrorCode
const (
ErrCodeNoError ErrCode = 0x100
ErrCodeGeneralProtocolError ErrCode = 0x101
ErrCodeInternalError ErrCode = 0x102
ErrCodeStreamCreationError ErrCode = 0x103
ErrCodeClosedCriticalStream ErrCode = 0x104
ErrCodeFrameUnexpected ErrCode = 0x105
ErrCodeFrameError ErrCode = 0x106
ErrCodeExcessiveLoad ErrCode = 0x107
ErrCodeIDError ErrCode = 0x108
ErrCodeSettingsError ErrCode = 0x109
ErrCodeMissingSettings ErrCode = 0x10a
ErrCodeRequestRejected ErrCode = 0x10b
ErrCodeRequestCanceled ErrCode = 0x10c
ErrCodeRequestIncomplete ErrCode = 0x10d
ErrCodeMessageError ErrCode = 0x10e
ErrCodeConnectError ErrCode = 0x10f
ErrCodeVersionFallback ErrCode = 0x110
ErrCodeDatagramError ErrCode = 0x33
ErrCodeNoError ErrCode = 0x100
ErrCodeGeneralProtocolError ErrCode = 0x101
ErrCodeInternalError ErrCode = 0x102
ErrCodeStreamCreationError ErrCode = 0x103
ErrCodeClosedCriticalStream ErrCode = 0x104
ErrCodeFrameUnexpected ErrCode = 0x105
ErrCodeFrameError ErrCode = 0x106
ErrCodeExcessiveLoad ErrCode = 0x107
ErrCodeIDError ErrCode = 0x108
ErrCodeSettingsError ErrCode = 0x109
ErrCodeMissingSettings ErrCode = 0x10a
ErrCodeRequestRejected ErrCode = 0x10b
ErrCodeRequestCanceled ErrCode = 0x10c
ErrCodeRequestIncomplete ErrCode = 0x10d
ErrCodeMessageError ErrCode = 0x10e
ErrCodeConnectError ErrCode = 0x10f
ErrCodeVersionFallback ErrCode = 0x110
ErrCodeDatagramError ErrCode = 0x33
ErrCodeQPACKDecompressionFailed ErrCode = 0x200
)
func (e ErrCode) String() string {
@@ -75,6 +76,8 @@ func (e ErrCode) string() string {
return "H3_VERSION_FALLBACK"
case ErrCodeDatagramError:
return "H3_DATAGRAM_ERROR"
case ErrCodeQPACKDecompressionFailed:
return "QPACK_DECOMPRESSION_FAILED"
default:
return ""
}
+23 -6
View File
@@ -179,6 +179,8 @@ func (f *headersFrame) Append(b []byte) []byte {
}
const (
// SETTINGS_MAX_FIELD_SECTION_SIZE
settingMaxFieldSectionSize = 0x6
// Extended CONNECT, RFC 9220
settingExtendedConnect = 0x8
// HTTP Datagrams, RFC 9297
@@ -186,10 +188,11 @@ const (
)
type settingsFrame struct {
Datagram bool // HTTP Datagrams, RFC 9297
ExtendedConnect bool // Extended CONNECT, RFC 9220
MaxFieldSectionSize int64 // SETTINGS_MAX_FIELD_SECTION_SIZE, -1 if not set
Other map[uint64]uint64 // all settings that we don't explicitly recognize
Datagram bool // HTTP Datagrams, RFC 9297
ExtendedConnect bool // Extended CONNECT, RFC 9220
Other map[uint64]uint64 // all settings that we don't explicitly recognize
}
func pointer[T any](v T) *T {
@@ -207,10 +210,10 @@ func parseSettingsFrame(r *countingByteReader, l uint64, streamID quic.StreamID,
}
return nil, err
}
frame := &settingsFrame{}
frame := &settingsFrame{MaxFieldSectionSize: -1}
b := bytes.NewReader(buf)
var settingsFrame qlog.SettingsFrame
var readDatagram, readExtendedConnect bool
settingsFrame := qlog.SettingsFrame{MaxFieldSectionSize: -1}
var readMaxFieldSectionSize, readDatagram, readExtendedConnect bool
for b.Len() > 0 {
id, err := quicvarint.Read(b)
if err != nil { // should not happen. We allocated the whole frame already.
@@ -222,6 +225,13 @@ func parseSettingsFrame(r *countingByteReader, l uint64, streamID quic.StreamID,
}
switch id {
case settingMaxFieldSectionSize:
if readMaxFieldSectionSize {
return nil, fmt.Errorf("duplicate setting: %d", id)
}
readMaxFieldSectionSize = true
frame.MaxFieldSectionSize = int64(val)
settingsFrame.MaxFieldSectionSize = int64(val)
case settingExtendedConnect:
if readExtendedConnect {
return nil, fmt.Errorf("duplicate setting: %d", id)
@@ -274,6 +284,9 @@ func parseSettingsFrame(r *countingByteReader, l uint64, streamID quic.StreamID,
func (f *settingsFrame) Append(b []byte) []byte {
b = quicvarint.Append(b, 0x4)
var l int
if f.MaxFieldSectionSize >= 0 {
l += quicvarint.Len(settingMaxFieldSectionSize) + quicvarint.Len(uint64(f.MaxFieldSectionSize))
}
for id, val := range f.Other {
l += quicvarint.Len(id) + quicvarint.Len(val)
}
@@ -284,6 +297,10 @@ func (f *settingsFrame) Append(b []byte) []byte {
l += quicvarint.Len(settingExtendedConnect) + quicvarint.Len(1)
}
b = quicvarint.Append(b, uint64(l))
if f.MaxFieldSectionSize >= 0 {
b = quicvarint.Append(b, settingMaxFieldSectionSize)
b = quicvarint.Append(b, uint64(f.MaxFieldSectionSize))
}
if f.Datagram {
b = quicvarint.Append(b, settingDatagram)
b = quicvarint.Append(b, 1)
+48 -13
View File
@@ -3,6 +3,7 @@ package http3
import (
"errors"
"fmt"
"io"
"net/http"
"net/textproto"
"net/url"
@@ -14,6 +15,13 @@ import (
"github.com/quic-go/qpack"
)
type qpackError struct{ err error }
func (e *qpackError) Error() string { return fmt.Sprintf("qpack: %v", e.err) }
func (e *qpackError) Unwrap() error { return e.err }
var errHeaderTooLarge = errors.New("http3: headers too large")
type header struct {
// Pseudo header fields defined in RFC 9114
Path string
@@ -38,11 +46,28 @@ var invalidHeaderFields = [...]string{
"upgrade",
}
func parseHeaders(headers []qpack.HeaderField, isRequest bool) (header, error) {
hdr := header{Headers: make(http.Header, len(headers))}
func parseHeaders(decodeFn qpack.DecodeFunc, isRequest bool, sizeLimit int, headerFields *[]qpack.HeaderField) (header, error) {
hdr := header{Headers: make(http.Header)}
var readFirstRegularHeader, readContentLength bool
var contentLengthStr string
for _, h := range headers {
for {
h, err := decodeFn()
if err != nil {
if err == io.EOF {
break
}
return header{}, &qpackError{err}
}
if headerFields != nil {
*headerFields = append(*headerFields, h)
}
// RFC 9114, section 4.2.2:
// The size of a field list is calculated based on the uncompressed size of fields,
// including the length of the name and value in bytes plus an overhead of 32 bytes for each field.
sizeLimit -= len(h.Name) + len(h.Value) + 32
if sizeLimit < 0 {
return header{}, errHeaderTooLarge
}
// field names need to be lowercase, see section 4.2 of RFC 9114
if strings.ToLower(h.Name) != h.Name {
return header{}, fmt.Errorf("header field is not lower-case: %s", h.Name)
@@ -130,19 +155,29 @@ func parseHeaders(headers []qpack.HeaderField, isRequest bool) (header, error) {
return hdr, nil
}
func parseTrailers(headers []qpack.HeaderField) (http.Header, error) {
h := make(http.Header, len(headers))
for _, field := range headers {
if field.IsPseudo() {
return nil, fmt.Errorf("http3: received pseudo header in trailer: %s", field.Name)
func parseTrailers(decodeFn qpack.DecodeFunc, headerFields *[]qpack.HeaderField) (http.Header, error) {
h := make(http.Header)
for {
hf, err := decodeFn()
if err != nil {
if err == io.EOF {
break
}
return nil, &qpackError{err}
}
h.Add(field.Name, field.Value)
if headerFields != nil {
*headerFields = append(*headerFields, hf)
}
if hf.IsPseudo() {
return nil, fmt.Errorf("http3: received pseudo header in trailer: %s", hf.Name)
}
h.Add(hf.Name, hf.Value)
}
return h, nil
}
func requestFromHeaders(headerFields []qpack.HeaderField) (*http.Request, error) {
hdr, err := parseHeaders(headerFields, true)
func requestFromHeaders(decodeFn qpack.DecodeFunc, sizeLimit int, headerFields *[]qpack.HeaderField) (*http.Request, error) {
hdr, err := parseHeaders(decodeFn, true, sizeLimit, headerFields)
if err != nil {
return nil, err
}
@@ -215,8 +250,8 @@ func requestFromHeaders(headerFields []qpack.HeaderField) (*http.Request, error)
// using the decoded qpack header filed.
// It is only called for the HTTP header (and not the HTTP trailer).
// It takes an http.Response as an argument to allow the caller to set the trailer later on.
func updateResponseFromHeaders(rsp *http.Response, headerFields []qpack.HeaderField) error {
hdr, err := parseHeaders(headerFields, false)
func updateResponseFromHeaders(rsp *http.Response, decodeFn qpack.DecodeFunc, sizeLimit int, headerFields *[]qpack.HeaderField) error {
hdr, err := parseHeaders(decodeFn, false, sizeLimit, headerFields)
if err != nil {
return err
}
+12 -3
View File
@@ -97,9 +97,10 @@ func (f *GoAwayFrame) encode(enc *jsontext.Encoder) error {
}
type SettingsFrame struct {
Datagram *bool
ExtendedConnect *bool
Other map[uint64]uint64
MaxFieldSectionSize int64
Datagram *bool
ExtendedConnect *bool
Other map[uint64]uint64
}
func (f *SettingsFrame) encode(enc *jsontext.Encoder) error {
@@ -109,6 +110,14 @@ func (f *SettingsFrame) encode(enc *jsontext.Encoder) error {
h.WriteToken(jsontext.String("settings"))
h.WriteToken(jsontext.String("settings"))
h.WriteToken(jsontext.BeginArray)
if f.MaxFieldSectionSize >= 0 {
h.WriteToken(jsontext.BeginObject)
h.WriteToken(jsontext.String("name"))
h.WriteToken(jsontext.String("settings_max_field_section_size"))
h.WriteToken(jsontext.String("value"))
h.WriteToken(jsontext.Uint(uint64(f.MaxFieldSectionSize)))
h.WriteToken(jsontext.EndObject)
}
if f.Datagram != nil {
h.WriteToken(jsontext.BeginObject)
h.WriteToken(jsontext.String("name"))
+43 -19
View File
@@ -454,14 +454,16 @@ func (s *Server) handleConn(conn *quic.Conn) error {
b := make([]byte, 0, 64)
b = quicvarint.Append(b, streamTypeControlStream) // stream type
b = (&settingsFrame{
Datagram: s.EnableDatagrams,
ExtendedConnect: true,
Other: s.AdditionalSettings,
MaxFieldSectionSize: int64(s.maxHeaderBytes()),
Datagram: s.EnableDatagrams,
ExtendedConnect: true,
Other: s.AdditionalSettings,
}).Append(b)
if qlogger != nil {
sf := qlog.SettingsFrame{
ExtendedConnect: pointer(true),
Other: maps.Clone(s.AdditionalSettings),
MaxFieldSectionSize: int64(s.maxHeaderBytes()),
ExtendedConnect: pointer(true),
Other: maps.Clone(s.AdditionalSettings),
}
if s.EnableDatagrams {
sf.Datagram = pointer(true)
@@ -570,16 +572,16 @@ func (s *Server) handleConn(conn *quic.Conn) error {
return handleErr
}
func (s *Server) maxHeaderBytes() uint64 {
func (s *Server) maxHeaderBytes() int {
if s.MaxHeaderBytes <= 0 {
return http.DefaultMaxHeaderBytes
}
return uint64(s.MaxHeaderBytes)
return s.MaxHeaderBytes
}
func (s *Server) handleRequest(
conn *Conn,
str datagramStream,
str *stateTrackingStream,
decoder *qpack.Decoder,
qlogger qlogwriter.Recorder,
) {
@@ -608,10 +610,12 @@ func (s *Server) handleRequest(
conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameUnexpected), "expected first frame to be a HEADERS frame")
return
}
if hf.Length > s.maxHeaderBytes() {
if hf.Length > uint64(s.maxHeaderBytes()) {
maybeQlogInvalidHeadersFrame(qlogger, str.StreamID(), hf.Length)
str.CancelRead(quic.StreamErrorCode(ErrCodeFrameError))
str.CancelWrite(quic.StreamErrorCode(ErrCodeFrameError))
// stop the client from sending more data
str.CancelRead(quic.StreamErrorCode(ErrCodeExcessiveLoad))
// send a 431 Response (Request Header Fields Too Large)
s.rejectWithHeaderFieldsTooLarge(str, conn, qlogger)
return
}
headerBlock := make([]byte, hf.Length)
@@ -621,19 +625,31 @@ func (s *Server) handleRequest(
str.CancelWrite(quic.StreamErrorCode(ErrCodeRequestIncomplete))
return
}
hfs, err := decoder.DecodeFull(headerBlock)
if err != nil {
// TODO: use the right error code
conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeGeneralProtocolError), "expected first frame to be a HEADERS frame")
return
decodeFn := decoder.Decode(headerBlock)
var hfs []qpack.HeaderField
if qlogger != nil {
hfs = make([]qpack.HeaderField, 0, 16)
}
req, err := requestFromHeaders(decodeFn, s.maxHeaderBytes(), &hfs)
if qlogger != nil {
qlogParsedHeadersFrame(qlogger, str.StreamID(), hf, hfs)
}
req, err := requestFromHeaders(hfs)
if err != nil {
str.CancelRead(quic.StreamErrorCode(ErrCodeMessageError))
str.CancelWrite(quic.StreamErrorCode(ErrCodeMessageError))
if errors.Is(err, errHeaderTooLarge) {
// stop the client from sending more data
str.CancelRead(quic.StreamErrorCode(ErrCodeExcessiveLoad))
// send a 431 Response (Request Header Fields Too Large)
s.rejectWithHeaderFieldsTooLarge(str, conn, qlogger)
return
}
errCode := ErrCodeMessageError
var qpackErr *qpackError
if errors.As(err, &qpackErr) {
errCode = ErrCodeQPACKDecompressionFailed
}
str.CancelRead(quic.StreamErrorCode(errCode))
str.CancelWrite(quic.StreamErrorCode(errCode))
return
}
@@ -713,6 +729,14 @@ func (s *Server) handleRequest(
str.Close()
}
func (s *Server) rejectWithHeaderFieldsTooLarge(str *stateTrackingStream, conn *Conn, qlogger qlogwriter.Recorder) {
hstr := newStream(str, conn, nil, nil, qlogger)
defer hstr.Close()
r := newResponseWriter(hstr, conn, false, s.Logger)
r.WriteHeader(http.StatusRequestHeaderFieldsTooLarge)
r.Flush()
}
// Close the server immediately, aborting requests and sending CONNECTION_CLOSE frames to connected clients.
// Close in combination with ListenAndServe() (instead of Serve()) may race if it is called before a UDP socket is established.
// It is the caller's responsibility to close any connection passed to ServeQUICConn.
+17 -13
View File
@@ -170,7 +170,7 @@ type RequestStream struct {
decoder *qpack.Decoder
requestWriter *requestWriter
maxHeaderBytes uint64
maxHeaderBytes int
reqDone chan<- struct{}
disableCompression bool
response *http.Response
@@ -186,7 +186,7 @@ func newRequestStream(
reqDone chan<- struct{},
decoder *qpack.Decoder,
disableCompression bool,
maxHeaderBytes uint64,
maxHeaderBytes int,
rsp *http.Response,
) *RequestStream {
return &RequestStream{
@@ -329,7 +329,7 @@ func (s *RequestStream) ReadResponse() (*http.Response, error) {
s.str.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameUnexpected), "expected first frame to be a HEADERS frame")
return nil, errors.New("http3: expected first frame to be a HEADERS frame")
}
if hf.Length > s.maxHeaderBytes {
if hf.Length > uint64(s.maxHeaderBytes) {
maybeQlogInvalidHeadersFrame(s.str.qlogger, s.str.StreamID(), hf.Length)
s.str.CancelRead(quic.StreamErrorCode(ErrCodeFrameError))
s.str.CancelWrite(quic.StreamErrorCode(ErrCodeFrameError))
@@ -342,20 +342,24 @@ func (s *RequestStream) ReadResponse() (*http.Response, error) {
s.str.CancelWrite(quic.StreamErrorCode(ErrCodeRequestIncomplete))
return nil, fmt.Errorf("http3: failed to read response headers: %w", err)
}
hfs, err := s.decoder.DecodeFull(headerBlock)
if err != nil {
maybeQlogInvalidHeadersFrame(s.str.qlogger, s.str.StreamID(), hf.Length)
// TODO: use the right error code
s.str.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeGeneralProtocolError), "")
return nil, fmt.Errorf("http3: failed to decode response headers: %w", err)
decodeFn := s.decoder.Decode(headerBlock)
var hfs []qpack.HeaderField
if s.str.qlogger != nil {
hfs = make([]qpack.HeaderField, 0, 16)
}
res := s.response
err = updateResponseFromHeaders(res, decodeFn, s.maxHeaderBytes, &hfs)
if s.str.qlogger != nil {
qlogParsedHeadersFrame(s.str.qlogger, s.str.StreamID(), hf, hfs)
}
res := s.response
if err := updateResponseFromHeaders(res, hfs); err != nil {
s.str.CancelRead(quic.StreamErrorCode(ErrCodeMessageError))
s.str.CancelWrite(quic.StreamErrorCode(ErrCodeMessageError))
if err != nil {
errCode := ErrCodeMessageError
var qpackErr *qpackError
if errors.As(err, &qpackErr) {
errCode = ErrCodeQPACKDecompressionFailed
}
s.str.CancelRead(quic.StreamErrorCode(errCode))
s.str.CancelWrite(quic.StreamErrorCode(errCode))
return nil, fmt.Errorf("http3: invalid response: %w", err)
}
+1 -1
View File
@@ -88,7 +88,7 @@ type Transport struct {
// MaxResponseHeaderBytes specifies a limit on how many response bytes are
// allowed in the server's response header.
// Zero means to use a default limit.
MaxResponseHeaderBytes int64
MaxResponseHeaderBytes int
// DisableCompression, if true, prevents the Transport from requesting compression with an
// "Accept-Encoding: gzip" request header when the Request contains no existing Accept-Encoding value.
@@ -155,6 +155,9 @@ func (h *appDataReceivedPacketTracker) isMissing(p protocol.PacketNumber) bool {
}
func (h *appDataReceivedPacketTracker) hasNewMissingPackets() bool {
if h.lastAck == nil {
return false
}
if h.largestObserved < reorderingThreshold {
return false
}
@@ -170,12 +173,6 @@ func (h *appDataReceivedPacketTracker) hasNewMissingPackets() bool {
}
func (h *appDataReceivedPacketTracker) shouldQueueACK(pn protocol.PacketNumber, ecn protocol.ECN, wasMissing bool) bool {
// always acknowledge the first packet
if h.lastAck == nil {
h.logger.Debugf("\tQueueing ACK because the first packet should be acknowledged.")
return true
}
// Send an ACK if this packet was reported missing in an ACK sent before.
// Ack decimation with reordering relies on the timer to send an ACK, but if
// missing packets we reported in the previous ACK, send an ACK immediately.
+18 -8
View File
@@ -387,19 +387,29 @@ func (h *cryptoSetup) GetSessionTicket() ([]byte, error) {
// We can't check h.tlsConfig here, since the actual config might have been obtained from
// the GetConfigForClient callback.
// See https://github.com/golang/go/issues/62032.
// Once that issue is resolved, this error assertion can be removed.
// This error assertion can be removed once we drop support for Go 1.25.
if strings.Contains(err.Error(), "session ticket keys unavailable") {
return nil, nil
}
return nil, err
}
ev := h.conn.NextEvent()
if ev.Kind != tls.QUICWriteData || ev.Level != tls.QUICEncryptionLevelApplication {
panic("crypto/tls bug: where's my session ticket?")
}
ticket := ev.Data
if ev := h.conn.NextEvent(); ev.Kind != tls.QUICNoEvent {
panic("crypto/tls bug: why more than one ticket?")
// If session tickets are disabled, NextEvent will immediately return QUICNoEvent,
// and we will return a nil ticket.
var ticket []byte
for {
ev := h.conn.NextEvent()
if ev.Kind == tls.QUICNoEvent {
break
}
if ev.Kind == tls.QUICWriteData && ev.Level == tls.QUICEncryptionLevelApplication {
if ticket != nil {
h.logger.Errorf("unexpected multiple session tickets")
continue
}
ticket = ev.Data
} else {
h.logger.Errorf("unexpected event: %v", ev.Kind)
}
}
return ticket, nil
}
+1
View File
@@ -115,6 +115,7 @@ func newFileSeq(w io.WriteCloser, pers string, odcid *ConnectionID, eventSchemas
runStopped: make(chan struct{}),
encodeErr: encodeErr,
events: make(chan event, eventChanSize),
eventSchemas: eventSchemas,
}
}
+1 -1
View File
@@ -29,7 +29,7 @@ loop:
MOVD $NUM_ROUNDS, R21
VLD1 (R11), [V30.S4, V31.S4]
// load contants
// load constants
// VLD4R (R10), [V0.S4, V1.S4, V2.S4, V3.S4]
WORD $0x4D60E940
+8 -2
View File
@@ -56,7 +56,10 @@ func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []
ret, out := sliceForAppend(dst, len(plaintext)+16)
if alias.InexactOverlap(out, plaintext) {
panic("chacha20poly1305: invalid buffer overlap")
panic("chacha20poly1305: invalid buffer overlap of output and input")
}
if alias.AnyOverlap(out, additionalData) {
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
}
chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
return ret
@@ -73,7 +76,10 @@ func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) (
ciphertext = ciphertext[:len(ciphertext)-16]
ret, out := sliceForAppend(dst, len(ciphertext))
if alias.InexactOverlap(out, ciphertext) {
panic("chacha20poly1305: invalid buffer overlap")
panic("chacha20poly1305: invalid buffer overlap of output and input")
}
if alias.AnyOverlap(out, additionalData) {
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
}
if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
for i := range out {
+8 -2
View File
@@ -31,7 +31,10 @@ func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []b
ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
ciphertext, tag := out[:len(plaintext)], out[len(plaintext):]
if alias.InexactOverlap(out, plaintext) {
panic("chacha20poly1305: invalid buffer overlap")
panic("chacha20poly1305: invalid buffer overlap of output and input")
}
if alias.AnyOverlap(out, additionalData) {
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
}
var polyKey [32]byte
@@ -67,7 +70,10 @@ func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []
ret, out := sliceForAppend(dst, len(ciphertext))
if alias.InexactOverlap(out, ciphertext) {
panic("chacha20poly1305: invalid buffer overlap")
panic("chacha20poly1305: invalid buffer overlap of output and input")
}
if alias.AnyOverlap(out, additionalData) {
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
}
if !p.Verify(tag) {
for i := range out {
+2 -2
View File
@@ -45,8 +45,8 @@ func IsValid(v string) bool {
// Canonical returns the canonical formatting of the semantic version v.
// It fills in any missing .MINOR or .PATCH and discards build metadata.
// Two semantic versions compare equal only if their canonical formattings
// are identical strings.
// Two semantic versions compare equal only if their canonical formatting
// is an identical string.
// The canonical invalid semantic version is the empty string.
func Canonical(v string) string {
p, ok := parse(v)
+52 -24
View File
@@ -280,6 +280,8 @@ type Framer struct {
// lastHeaderStream is non-zero if the last frame was an
// unfinished HEADERS/CONTINUATION.
lastHeaderStream uint32
// lastFrameType holds the type of the last frame for verifying frame order.
lastFrameType FrameType
maxReadSize uint32
headerBuf [frameHeaderLen]byte
@@ -488,30 +490,41 @@ func terminalReadFrameError(err error) bool {
return err != nil
}
// ReadFrame reads a single frame. The returned Frame is only valid
// until the next call to ReadFrame.
// ReadFrameHeader reads the header of the next frame.
// It reads the 9-byte fixed frame header, and does not read any portion of the
// frame payload. The caller is responsible for consuming the payload, either
// with ReadFrameForHeader or directly from the Framer's io.Reader.
//
// If the frame is larger than previously set with SetMaxReadFrameSize, the
// returned error is ErrFrameTooLarge. Other errors may be of type
// ConnectionError, StreamError, or anything else from the underlying
// reader.
// If the frame is larger than previously set with SetMaxReadFrameSize, it
// returns the frame header and ErrFrameTooLarge.
//
// 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) {
// If the returned FrameHeader.StreamID is non-zero, it indicates the stream
// responsible for the error.
func (fr *Framer) ReadFrameHeader() (FrameHeader, error) {
fr.errDetail = nil
if fr.lastFrame != nil {
fr.lastFrame.invalidate()
}
fh, err := readFrameHeader(fr.headerBuf[:], fr.r)
if err != nil {
return nil, err
return fh, err
}
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", ErrFrameTooLarge)
return fh, fmt.Errorf("http2: failed reading the frame payload: %w, note that the frame header looked like an HTTP/1.1 header", ErrFrameTooLarge)
}
return nil, ErrFrameTooLarge
return fh, ErrFrameTooLarge
}
if err := fr.checkFrameOrder(fh); err != nil {
return fh, err
}
return fh, nil
}
// ReadFrameForHeader reads the payload for the frame with the given FrameHeader.
//
// It behaves identically to ReadFrame, other than not checking the maximum
// frame size.
func (fr *Framer) ReadFrameForHeader(fh FrameHeader) (Frame, error) {
if fr.lastFrame != nil {
fr.lastFrame.invalidate()
}
payload := fr.getReadBuf(fh.Length)
if _, err := io.ReadFull(fr.r, payload); err != nil {
@@ -527,9 +540,7 @@ func (fr *Framer) ReadFrame() (Frame, error) {
}
return nil, err
}
if err := fr.checkFrameOrder(f); err != nil {
return nil, err
}
fr.lastFrame = f
if fr.logReads {
fr.debugReadLoggerf("http2: Framer %p: read %v", fr, summarizeFrame(f))
}
@@ -539,6 +550,24 @@ func (fr *Framer) ReadFrame() (Frame, error) {
return f, nil
}
// ReadFrame reads a single frame. The returned Frame is only valid
// until the next call to ReadFrame or ReadFrameBodyForHeader.
//
// If the frame is larger than previously set with SetMaxReadFrameSize, the
// 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) {
fh, err := fr.ReadFrameHeader()
if err != nil {
return nil, err
}
return fr.ReadFrameForHeader(fh)
}
// connError returns ConnectionError(code) but first
// stashes away a public reason to the caller can optionally relay it
// to the peer before hanging up on them. This might help others debug
@@ -551,20 +580,19 @@ func (fr *Framer) connError(code ErrCode, reason string) error {
// checkFrameOrder reports an error if f is an invalid frame to return
// next from ReadFrame. Mostly it checks whether HEADERS and
// CONTINUATION frames are contiguous.
func (fr *Framer) checkFrameOrder(f Frame) error {
last := fr.lastFrame
fr.lastFrame = f
func (fr *Framer) checkFrameOrder(fh FrameHeader) error {
lastType := fr.lastFrameType
fr.lastFrameType = fh.Type
if fr.AllowIllegalReads {
return nil
}
fh := f.Header()
if fr.lastHeaderStream != 0 {
if fh.Type != FrameContinuation {
return fr.connError(ErrCodeProtocol,
fmt.Sprintf("got %s for stream %d; expected CONTINUATION following %s for stream %d",
fh.Type, fh.StreamID,
last.Header().Type, fr.lastHeaderStream))
lastType, fr.lastHeaderStream))
}
if fh.StreamID != fr.lastHeaderStream {
return fr.connError(ErrCodeProtocol,
@@ -1161,7 +1189,7 @@ var defaultRFC9218Priority = PriorityParam{
// PriorityParam struct below is a superset of both schemes. The exported
// symbols are from RFC 7540 and the non-exported ones are from RFC 9218.
// PriorityParam are the stream prioritzation parameters.
// PriorityParam are the stream prioritization parameters.
type PriorityParam struct {
// StreamDep is a 31-bit stream identifier for the
// stream that this stream depends on. Zero means no
+86 -18
View File
@@ -9,6 +9,7 @@ package http2
import (
"bufio"
"bytes"
"compress/flate"
"compress/gzip"
"context"
"crypto/rand"
@@ -3076,35 +3077,102 @@ type erringRoundTripper struct{ err error }
func (rt erringRoundTripper) RoundTripErr() error { return rt.err }
func (rt erringRoundTripper) RoundTrip(*http.Request) (*http.Response, error) { return nil, rt.err }
var errConcurrentReadOnResBody = errors.New("http2: concurrent read on response body")
// gzipReader wraps a response body so it can lazily
// call gzip.NewReader on the first call to Read
// get gzip.Reader from the pool on the first call to Read.
// After Close is called it puts gzip.Reader to the pool immediately
// if there is no Read in progress or later when Read completes.
type gzipReader struct {
_ incomparable
body io.ReadCloser // underlying Response.Body
zr *gzip.Reader // lazily-initialized gzip reader
zerr error // sticky error
mu sync.Mutex // guards zr and zerr
zr *gzip.Reader // stores gzip reader from the pool between reads
zerr error // sticky gzip reader init error or sentinel value to detect concurrent read and read after close
}
type eofReader struct{}
func (eofReader) Read([]byte) (int, error) { return 0, io.EOF }
func (eofReader) ReadByte() (byte, error) { return 0, io.EOF }
var gzipPool = sync.Pool{New: func() any { return new(gzip.Reader) }}
// gzipPoolGet gets a gzip.Reader from the pool and resets it to read from r.
func gzipPoolGet(r io.Reader) (*gzip.Reader, error) {
zr := gzipPool.Get().(*gzip.Reader)
if err := zr.Reset(r); err != nil {
gzipPoolPut(zr)
return nil, err
}
return zr, nil
}
// gzipPoolPut puts a gzip.Reader back into the pool.
func gzipPoolPut(zr *gzip.Reader) {
// Reset will allocate bufio.Reader if we pass it anything
// other than a flate.Reader, so ensure that it's getting one.
var r flate.Reader = eofReader{}
zr.Reset(r)
gzipPool.Put(zr)
}
// acquire returns a gzip.Reader for reading response body.
// The reader must be released after use.
func (gz *gzipReader) acquire() (*gzip.Reader, error) {
gz.mu.Lock()
defer gz.mu.Unlock()
if gz.zerr != nil {
return nil, gz.zerr
}
if gz.zr == nil {
gz.zr, gz.zerr = gzipPoolGet(gz.body)
if gz.zerr != nil {
return nil, gz.zerr
}
}
ret := gz.zr
gz.zr, gz.zerr = nil, errConcurrentReadOnResBody
return ret, nil
}
// release returns the gzip.Reader to the pool if Close was called during Read.
func (gz *gzipReader) release(zr *gzip.Reader) {
gz.mu.Lock()
defer gz.mu.Unlock()
if gz.zerr == errConcurrentReadOnResBody {
gz.zr, gz.zerr = zr, nil
} else { // fs.ErrClosed
gzipPoolPut(zr)
}
}
// close returns the gzip.Reader to the pool immediately or
// signals release to do so after Read completes.
func (gz *gzipReader) close() {
gz.mu.Lock()
defer gz.mu.Unlock()
if gz.zerr == nil && gz.zr != nil {
gzipPoolPut(gz.zr)
gz.zr = nil
}
gz.zerr = fs.ErrClosed
}
func (gz *gzipReader) Read(p []byte) (n int, err error) {
if gz.zerr != nil {
return 0, gz.zerr
zr, err := gz.acquire()
if err != nil {
return 0, err
}
if gz.zr == nil {
gz.zr, err = gzip.NewReader(gz.body)
if err != nil {
gz.zerr = err
return 0, err
}
}
return gz.zr.Read(p)
defer gz.release(zr)
return zr.Read(p)
}
func (gz *gzipReader) Close() error {
if err := gz.body.Close(); err != nil {
return err
}
gz.zerr = fs.ErrClosed
return nil
gz.close()
return gz.body.Close()
}
type errorReader struct{ err error }
+50 -15
View File
@@ -185,45 +185,75 @@ func (wr *FrameWriteRequest) replyToWriter(err error) {
}
// writeQueue is used by implementations of WriteScheduler.
//
// Each writeQueue contains a queue of FrameWriteRequests, meant to store all
// FrameWriteRequests associated with a given stream. This is implemented as a
// two-stage queue: currQueue[currPos:] and nextQueue. Removing an item is done
// by incrementing currPos of currQueue. Adding an item is done by appending it
// to the nextQueue. If currQueue is empty when trying to remove an item, we
// can swap currQueue and nextQueue to remedy the situation.
// This two-stage queue is analogous to the use of two lists in Okasaki's
// purely functional queue but without the overhead of reversing the list when
// swapping stages.
//
// writeQueue also contains prev and next, this can be used by implementations
// of WriteScheduler to construct data structures that represent the order of
// writing between different streams (e.g. circular linked list).
type writeQueue struct {
s []FrameWriteRequest
currQueue []FrameWriteRequest
nextQueue []FrameWriteRequest
currPos int
prev, next *writeQueue
}
func (q *writeQueue) empty() bool { return len(q.s) == 0 }
func (q *writeQueue) empty() bool {
return (len(q.currQueue) - q.currPos + len(q.nextQueue)) == 0
}
func (q *writeQueue) push(wr FrameWriteRequest) {
q.s = append(q.s, wr)
q.nextQueue = append(q.nextQueue, wr)
}
func (q *writeQueue) shift() FrameWriteRequest {
if len(q.s) == 0 {
if q.empty() {
panic("invalid use of queue")
}
wr := q.s[0]
// TODO: less copy-happy queue.
copy(q.s, q.s[1:])
q.s[len(q.s)-1] = FrameWriteRequest{}
q.s = q.s[:len(q.s)-1]
if q.currPos >= len(q.currQueue) {
q.currQueue, q.currPos, q.nextQueue = q.nextQueue, 0, q.currQueue[:0]
}
wr := q.currQueue[q.currPos]
q.currQueue[q.currPos] = FrameWriteRequest{}
q.currPos++
return wr
}
func (q *writeQueue) peek() *FrameWriteRequest {
if q.currPos < len(q.currQueue) {
return &q.currQueue[q.currPos]
}
if len(q.nextQueue) > 0 {
return &q.nextQueue[0]
}
return nil
}
// consume consumes up to n bytes from q.s[0]. If the frame is
// entirely consumed, it is removed from the queue. If the frame
// is partially consumed, the frame is kept with the consumed
// bytes removed. Returns true iff any bytes were consumed.
func (q *writeQueue) consume(n int32) (FrameWriteRequest, bool) {
if len(q.s) == 0 {
if q.empty() {
return FrameWriteRequest{}, false
}
consumed, rest, numresult := q.s[0].Consume(n)
consumed, rest, numresult := q.peek().Consume(n)
switch numresult {
case 0:
return FrameWriteRequest{}, false
case 1:
q.shift()
case 2:
q.s[0] = rest
*q.peek() = rest
}
return consumed, true
}
@@ -232,10 +262,15 @@ type writeQueuePool []*writeQueue
// put inserts an unused writeQueue into the pool.
func (p *writeQueuePool) put(q *writeQueue) {
for i := range q.s {
q.s[i] = FrameWriteRequest{}
for i := range q.currQueue {
q.currQueue[i] = FrameWriteRequest{}
}
q.s = q.s[:0]
for i := range q.nextQueue {
q.nextQueue[i] = FrameWriteRequest{}
}
q.currQueue = q.currQueue[:0]
q.nextQueue = q.nextQueue[:0]
q.currPos = 0
*p = append(*p, q)
}
+2 -3
View File
@@ -214,8 +214,8 @@ func (z sortPriorityNodeSiblingsRFC7540) Swap(i, k int) { z[i], z[k] = z[k], z[i
func (z sortPriorityNodeSiblingsRFC7540) Less(i, k int) bool {
// Prefer the subtree that has sent fewer bytes relative to its weight.
// See sections 5.3.2 and 5.3.4.
wi, bi := float64(z[i].weight+1), float64(z[i].subtreeBytes)
wk, bk := float64(z[k].weight+1), float64(z[k].subtreeBytes)
wi, bi := float64(z[i].weight)+1, float64(z[i].subtreeBytes)
wk, bk := float64(z[k].weight)+1, float64(z[k].subtreeBytes)
if bi == 0 && bk == 0 {
return wi >= wk
}
@@ -302,7 +302,6 @@ func (ws *priorityWriteSchedulerRFC7540) CloseStream(streamID uint32) {
q := n.q
ws.queuePool.put(&q)
n.q.s = nil
if ws.maxClosedNodesInTree > 0 {
ws.addClosedOrIdleNode(&ws.closedNodes, ws.maxClosedNodesInTree, n)
} else {
@@ -39,7 +39,7 @@ type priorityWriteSchedulerRFC9218 struct {
prioritizeIncremental bool
}
func newPriorityWriteSchedulerRFC9128() WriteScheduler {
func newPriorityWriteSchedulerRFC9218() WriteScheduler {
ws := &priorityWriteSchedulerRFC9218{
streams: make(map[uint32]streamMetadata),
}
+16 -1
View File
@@ -467,7 +467,9 @@ func (c Cursor) FindByPos(start, end token.Pos) (Cursor, bool) {
// This algorithm could be implemented using c.Inspect,
// but it is about 2.5x slower.
best := int32(-1) // push index of latest (=innermost) node containing range
// best is the push-index of the latest (=innermost) node containing range.
// (Beware: latest is not always innermost because FuncDecl.{Name,Type} overlap.)
best := int32(-1)
for i, limit := c.indices(); i < limit; i++ {
ev := events[i]
if ev.index > i { // push?
@@ -481,6 +483,19 @@ func (c Cursor) FindByPos(start, end token.Pos) (Cursor, bool) {
continue
}
} else {
// Edge case: FuncDecl.Name and .Type overlap:
// Don't update best from Name to FuncDecl.Type.
//
// The condition can be read as:
// - n is FuncType
// - n.parent is FuncDecl
// - best is strictly beneath the FuncDecl
if ev.typ == 1<<nFuncType &&
events[ev.parent].typ == 1<<nFuncDecl &&
best > ev.parent {
continue
}
nodeEnd = n.End()
if n.Pos() > start {
break // disjoint, after; stop
+1 -1
View File
@@ -78,7 +78,7 @@ func PrintErrors(pkgs []*Package) int {
return n
}
// Postorder returns an iterator over the the packages in
// Postorder returns an iterator over the packages in
// the import graph whose roots are pkg.
// Packages are enumerated in dependencies-first order.
func Postorder(pkgs []*Package) iter.Seq[*Package] {
+2 -2
View File
@@ -249,7 +249,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
case *types.Func:
// A func, if not package-level, must be a method.
if recv := obj.Type().(*types.Signature).Recv(); recv == nil {
if recv := obj.Signature().Recv(); recv == nil {
return "", fmt.Errorf("func is not a method: %v", obj)
}
@@ -405,7 +405,7 @@ func (enc *Encoder) concreteMethod(meth *types.Func) (Path, bool) {
return "", false
}
_, named := typesinternal.ReceiverNamed(meth.Type().(*types.Signature).Recv())
_, named := typesinternal.ReceiverNamed(meth.Signature().Recv())
if named == nil {
return "", false
}
+1 -2
View File
@@ -304,8 +304,7 @@ func (h hasher) hash(t types.Type) uint32 {
case *types.Named:
hash := h.hashTypeName(t.Obj())
targs := t.TypeArgs()
for i := 0; i < targs.Len(); i++ {
targ := targs.At(i)
for targ := range targs.Types() {
hash += 2 * h.hash(targ)
}
return hash
+1 -1
View File
@@ -34,7 +34,7 @@ type fileInfo struct {
const maxlines = 64 * 1024
func (s *fakeFileSet) pos(file string, line, column int) token.Pos {
// TODO(mdempsky): Make use of column.
_ = column // TODO(mdempsky): Make use of column.
// Since we don't know the set of needed file positions, we reserve maxlines
// positions per file. We delay calling token.File.SetLines until all
+22 -14
View File
@@ -829,8 +829,7 @@ func (p *iexporter) doDecl(obj types.Object) {
// their name must be qualified before exporting recv.
if rparams := sig.RecvTypeParams(); rparams.Len() > 0 {
prefix := obj.Name() + "." + m.Name()
for i := 0; i < rparams.Len(); i++ {
rparam := rparams.At(i)
for rparam := range rparams.TypeParams() {
name := tparamExportName(prefix, rparam)
w.p.tparamNames[rparam.Obj()] = name
}
@@ -944,6 +943,13 @@ func (w *exportWriter) posV0(pos token.Pos) {
}
func (w *exportWriter) pkg(pkg *types.Package) {
if pkg == nil {
// [exportWriter.typ] accepts a nil pkg only for types
// of constants, which cannot contain named objects
// such as fields or methods and thus should never
// reach this method (#76222).
panic("nil package")
}
// Ensure any referenced packages are declared in the main index.
w.p.allPkgs[pkg] = true
@@ -959,9 +965,11 @@ func (w *exportWriter) qualifiedType(obj *types.TypeName) {
w.pkg(obj.Pkg())
}
// TODO(rfindley): what does 'pkg' even mean here? It would be better to pass
// it in explicitly into signatures and structs that may use it for
// constructing fields.
// typ emits the specified type.
//
// Objects within the type (struct fields and interface methods) are
// qualified by pkg. It may be nil if the type cannot contain objects,
// such as the type of a constant.
func (w *exportWriter) typ(t types.Type, pkg *types.Package) {
w.data.uint64(w.p.typOff(t, pkg))
}
@@ -991,6 +999,7 @@ func (w *exportWriter) startType(k itag) {
w.data.uint64(uint64(k))
}
// doTyp is the implementation of [exportWriter.typ].
func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
if trace {
w.p.trace("exporting type %s (%T)", t, t)
@@ -1064,7 +1073,7 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
case *types.Signature:
w.startType(signatureType)
w.pkg(pkg)
w.pkg(pkg) // qualifies param/result vars
w.signature(t)
case *types.Struct:
@@ -1110,19 +1119,19 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
case *types.Interface:
w.startType(interfaceType)
w.pkg(pkg)
w.pkg(pkg) // qualifies unexported method funcs
n := t.NumEmbeddeds()
w.uint64(uint64(n))
for i := 0; i < n; i++ {
ft := t.EmbeddedType(i)
tPkg := pkg
if named, _ := types.Unalias(ft).(*types.Named); named != nil {
w.pos(named.Obj().Pos())
} else {
// e.g. ~int
w.pos(token.NoPos)
}
w.typ(ft, tPkg)
w.typ(ft, pkg)
}
// See comment for struct fields. In shallow mode we change the encoding
@@ -1223,20 +1232,19 @@ func (w *exportWriter) signature(sig *types.Signature) {
func (w *exportWriter) typeList(ts *types.TypeList, pkg *types.Package) {
w.uint64(uint64(ts.Len()))
for i := 0; i < ts.Len(); i++ {
w.typ(ts.At(i), pkg)
for t := range ts.Types() {
w.typ(t, pkg)
}
}
func (w *exportWriter) tparamList(prefix string, list *types.TypeParamList, pkg *types.Package) {
ll := uint64(list.Len())
w.uint64(ll)
for i := 0; i < list.Len(); i++ {
tparam := list.At(i)
for tparam := range list.TypeParams() {
// Set the type parameter exportName before exporting its type.
exportName := tparamExportName(prefix, tparam)
w.p.tparamNames[tparam.Obj()] = exportName
w.typ(list.At(i), pkg)
w.typ(tparam, pkg)
}
}
+30 -30
View File
@@ -432,10 +432,10 @@ func (p *iimporter) doDecl(pkg *types.Package, name string) {
errorf("%v.%v not in index", pkg, name)
}
r := &importReader{p: p, currPkg: pkg}
r := &importReader{p: p}
r.declReader.Reset(p.declData[off:])
r.obj(name)
r.obj(pkg, name)
}
func (p *iimporter) stringAt(off uint64) string {
@@ -551,7 +551,6 @@ func canReuse(def *types.Named, rhs types.Type) bool {
type importReader struct {
p *iimporter
declReader bytes.Reader
currPkg *types.Package
prevFile string
prevLine int64
prevColumn int64
@@ -565,7 +564,8 @@ type importReader struct {
// for 1.24, but the fix was not worth back-porting).
var markBlack = func(name *types.TypeName) {}
func (r *importReader) obj(name string) {
// obj decodes and declares the package-level object denoted by (pkg, name).
func (r *importReader) obj(pkg *types.Package, name string) {
tag := r.byte()
pos := r.pos()
@@ -576,27 +576,27 @@ func (r *importReader) obj(name string) {
tparams = r.tparamList()
}
typ := r.typ()
obj := aliases.NewAlias(r.p.aliases, pos, r.currPkg, name, typ, tparams)
obj := aliases.NewAlias(r.p.aliases, pos, pkg, name, typ, tparams)
markBlack(obj) // workaround for golang/go#69912
r.declare(obj)
case constTag:
typ, val := r.value()
r.declare(types.NewConst(pos, r.currPkg, name, typ, val))
r.declare(types.NewConst(pos, pkg, name, typ, val))
case funcTag, genericFuncTag:
var tparams []*types.TypeParam
if tag == genericFuncTag {
tparams = r.tparamList()
}
sig := r.signature(nil, nil, tparams)
r.declare(types.NewFunc(pos, r.currPkg, name, sig))
sig := r.signature(pkg, nil, nil, tparams)
r.declare(types.NewFunc(pos, pkg, name, sig))
case typeTag, genericTypeTag:
// Types can be recursive. We need to setup a stub
// declaration before recursing.
obj := types.NewTypeName(pos, r.currPkg, name, nil)
obj := types.NewTypeName(pos, pkg, name, nil)
named := types.NewNamed(obj, nil, nil)
markBlack(obj) // workaround for golang/go#69912
@@ -616,7 +616,7 @@ func (r *importReader) obj(name string) {
for n := r.uint64(); n > 0; n-- {
mpos := r.pos()
mname := r.ident()
recv := r.param()
recv := r.param(pkg)
// If the receiver has any targs, set those as the
// rparams of the method (since those are the
@@ -630,9 +630,9 @@ func (r *importReader) obj(name string) {
rparams[i] = types.Unalias(targs.At(i)).(*types.TypeParam)
}
}
msig := r.signature(recv, rparams, nil)
msig := r.signature(pkg, recv, rparams, nil)
named.AddMethod(types.NewFunc(mpos, r.currPkg, mname, msig))
named.AddMethod(types.NewFunc(mpos, pkg, mname, msig))
}
}
@@ -644,12 +644,12 @@ func (r *importReader) obj(name string) {
errorf("unexpected type param type")
}
name0 := tparamName(name)
tn := types.NewTypeName(pos, r.currPkg, name0, nil)
tn := types.NewTypeName(pos, pkg, name0, nil)
t := types.NewTypeParam(tn, nil)
// To handle recursive references to the typeparam within its
// bound, save the partial type in tparamIndex before reading the bounds.
id := ident{r.currPkg, name}
id := ident{pkg, name}
r.p.tparamIndex[id] = t
var implicit bool
if r.p.version >= iexportVersionGo1_18 {
@@ -672,7 +672,7 @@ func (r *importReader) obj(name string) {
case varTag:
typ := r.typ()
v := types.NewVar(pos, r.currPkg, name, typ)
v := types.NewVar(pos, pkg, name, typ)
typesinternal.SetVarKind(v, typesinternal.PackageVar)
r.declare(v)
@@ -905,11 +905,11 @@ func (r *importReader) doType(base *types.Named) (res types.Type) {
case mapType:
return types.NewMap(r.typ(), r.typ())
case signatureType:
r.currPkg = r.pkg()
return r.signature(nil, nil, nil)
paramPkg := r.pkg()
return r.signature(paramPkg, nil, nil, nil)
case structType:
r.currPkg = r.pkg()
fieldPkg := r.pkg()
fields := make([]*types.Var, r.uint64())
tags := make([]string, len(fields))
@@ -932,7 +932,7 @@ func (r *importReader) doType(base *types.Named) (res types.Type) {
// discussed in iexport.go, this is not correct, but mostly works and is
// preferable to failing (for now at least).
if field == nil {
field = types.NewField(fpos, r.currPkg, fname, ftyp, emb)
field = types.NewField(fpos, fieldPkg, fname, ftyp, emb)
}
fields[i] = field
@@ -941,7 +941,7 @@ func (r *importReader) doType(base *types.Named) (res types.Type) {
return types.NewStruct(fields, tags)
case interfaceType:
r.currPkg = r.pkg()
methodPkg := r.pkg() // qualifies methods and their param/result vars
embeddeds := make([]types.Type, r.uint64())
for i := range embeddeds {
@@ -963,12 +963,12 @@ func (r *importReader) doType(base *types.Named) (res types.Type) {
// don't agree with this.
var recv *types.Var
if base != nil {
recv = types.NewVar(token.NoPos, r.currPkg, "", base)
recv = types.NewVar(token.NoPos, methodPkg, "", base)
}
msig := r.signature(recv, nil, nil)
msig := r.signature(methodPkg, recv, nil, nil)
if method == nil {
method = types.NewFunc(mpos, r.currPkg, mname, msig)
method = types.NewFunc(mpos, methodPkg, mname, msig)
}
methods[i] = method
}
@@ -1049,9 +1049,9 @@ func (r *importReader) objectPathObject() types.Object {
return obj
}
func (r *importReader) signature(recv *types.Var, rparams []*types.TypeParam, tparams []*types.TypeParam) *types.Signature {
params := r.paramList()
results := r.paramList()
func (r *importReader) signature(paramPkg *types.Package, recv *types.Var, rparams []*types.TypeParam, tparams []*types.TypeParam) *types.Signature {
params := r.paramList(paramPkg)
results := r.paramList(paramPkg)
variadic := params.Len() > 0 && r.bool()
return types.NewSignatureType(recv, rparams, tparams, params, results, variadic)
}
@@ -1070,19 +1070,19 @@ func (r *importReader) tparamList() []*types.TypeParam {
return xs
}
func (r *importReader) paramList() *types.Tuple {
func (r *importReader) paramList(pkg *types.Package) *types.Tuple {
xs := make([]*types.Var, r.uint64())
for i := range xs {
xs[i] = r.param()
xs[i] = r.param(pkg)
}
return types.NewTuple(xs...)
}
func (r *importReader) param() *types.Var {
func (r *importReader) param(pkg *types.Package) *types.Var {
pos := r.pos()
name := r.ident()
typ := r.typ()
return types.NewParam(pos, r.currPkg, name, typ)
return types.NewParam(pos, pkg, name, typ)
}
func (r *importReader) bool() bool {
+462 -308
View File
@@ -12,354 +12,508 @@ type pkginfo struct {
}
var deps = [...]pkginfo{
{"archive/tar", "\x03k\x03E;\x01\n\x01$\x01\x01\x02\x05\b\x02\x01\x02\x02\f"},
{"archive/zip", "\x02\x04a\a\x03\x12\x021;\x01+\x05\x01\x0f\x03\x02\x0e\x04"},
{"bufio", "\x03k\x83\x01D\x14"},
{"bytes", "n*Y\x03\fG\x02\x02"},
{"archive/tar", "\x03n\x03E<\x01\n\x01$\x01\x01\x02\x05\b\x02\x01\x02\x02\f"},
{"archive/zip", "\x02\x04d\a\x03\x12\x021<\x01+\x05\x01\x0f\x03\x02\x0e\x04"},
{"bufio", "\x03n\x84\x01D\x14"},
{"bytes", "q*Z\x03\fG\x02\x02"},
{"cmp", ""},
{"compress/bzip2", "\x02\x02\xed\x01A"},
{"compress/flate", "\x02l\x03\x80\x01\f\x033\x01\x03"},
{"compress/gzip", "\x02\x04a\a\x03\x14lT"},
{"compress/lzw", "\x02l\x03\x80\x01"},
{"compress/zlib", "\x02\x04a\a\x03\x12\x01m"},
{"container/heap", "\xb3\x02"},
{"compress/bzip2", "\x02\x02\xf1\x01A"},
{"compress/flate", "\x02o\x03\x81\x01\f\x033\x01\x03"},
{"compress/gzip", "\x02\x04d\a\x03\x14mT"},
{"compress/lzw", "\x02o\x03\x81\x01"},
{"compress/zlib", "\x02\x04d\a\x03\x12\x01n"},
{"container/heap", "\xb7\x02"},
{"container/list", ""},
{"container/ring", ""},
{"context", "n\\m\x01\r"},
{"crypto", "\x83\x01nC"},
{"crypto/aes", "\x10\n\a\x93\x02"},
{"crypto/cipher", "\x03\x1e\x01\x01\x1e\x11\x1c+X"},
{"crypto/des", "\x10\x13\x1e-+\x9b\x01\x03"},
{"crypto/dsa", "A\x04)\x83\x01\r"},
{"crypto/ecdh", "\x03\v\f\x0e\x04\x15\x04\r\x1c\x83\x01"},
{"crypto/ecdsa", "\x0e\x05\x03\x04\x01\x0e\a\v\x05\x01\x04\f\x01\x1c\x83\x01\r\x05K\x01"},
{"crypto/ed25519", "\x0e\x1c\x11\x06\n\a\x1c\x83\x01C"},
{"crypto/elliptic", "0>\x83\x01\r9"},
{"crypto/fips140", " \x05"},
{"crypto/hkdf", "-\x13\x01-\x15"},
{"crypto/hmac", "\x1a\x14\x12\x01\x111"},
{"crypto/internal/boring", "\x0e\x02\rf"},
{"crypto/internal/boring/bbig", "\x1a\xe4\x01M"},
{"crypto/internal/boring/bcache", "\xb8\x02\x13"},
{"context", "q[o\x01\r"},
{"crypto", "\x86\x01oC"},
{"crypto/aes", "\x10\n\t\x95\x02"},
{"crypto/cipher", "\x03 \x01\x01\x1f\x11\x1c+Y"},
{"crypto/des", "\x10\x15\x1f-+\x9c\x01\x03"},
{"crypto/dsa", "D\x04)\x84\x01\r"},
{"crypto/ecdh", "\x03\v\f\x10\x04\x16\x04\r\x1c\x84\x01"},
{"crypto/ecdsa", "\x0e\x05\x03\x04\x01\x10\a\v\x06\x01\x04\f\x01\x1c\x84\x01\r\x05K\x01"},
{"crypto/ed25519", "\x0e\x1e\x11\a\n\a\x1c\x84\x01C"},
{"crypto/elliptic", "2?\x84\x01\r9"},
{"crypto/fips140", "\"\x05"},
{"crypto/hkdf", "/\x14\x01-\x15"},
{"crypto/hmac", "\x1a\x16\x13\x01\x111"},
{"crypto/internal/boring", "\x0e\x02\ri"},
{"crypto/internal/boring/bbig", "\x1a\xe8\x01M"},
{"crypto/internal/boring/bcache", "\xbc\x02\x13"},
{"crypto/internal/boring/sig", ""},
{"crypto/internal/cryptotest", "\x03\r\n\x06$\x0e\x19\x06\x12\x12 \x04\a\t\x16\x01\x11\x11\x1b\x01\a\x05\b\x03\x05\v"},
{"crypto/internal/entropy", "F"},
{"crypto/internal/fips140", "?/\x15\xa7\x01\v\x16"},
{"crypto/internal/fips140/aes", "\x03\x1d\x03\x02\x13\x05\x01\x01\x05*\x92\x014"},
{"crypto/internal/fips140/aes/gcm", " \x01\x02\x02\x02\x11\x05\x01\x06*\x8f\x01"},
{"crypto/internal/fips140/alias", "\xcb\x02"},
{"crypto/internal/fips140/bigmod", "%\x18\x01\x06*\x92\x01"},
{"crypto/internal/fips140/check", " \x0e\x06\t\x02\xb2\x01Z"},
{"crypto/internal/fips140/check/checktest", "%\x85\x02!"},
{"crypto/internal/fips140/drbg", "\x03\x1c\x01\x01\x04\x13\x05\b\x01(\x83\x01\x0f7"},
{"crypto/internal/fips140/ecdh", "\x03\x1d\x05\x02\t\r1\x83\x01\x0f7"},
{"crypto/internal/fips140/ecdsa", "\x03\x1d\x04\x01\x02\a\x02\x068\x15nF"},
{"crypto/internal/fips140/ed25519", "\x03\x1d\x05\x02\x04\v8\xc6\x01\x03"},
{"crypto/internal/fips140/edwards25519", "%\a\f\x051\x92\x017"},
{"crypto/internal/fips140/edwards25519/field", "%\x13\x051\x92\x01"},
{"crypto/internal/fips140/hkdf", "\x03\x1d\x05\t\x06:\x15"},
{"crypto/internal/fips140/hmac", "\x03\x1d\x14\x01\x018\x15"},
{"crypto/internal/fips140/mlkem", "\x03\x1d\x05\x02\x0e\x03\x051"},
{"crypto/internal/fips140/nistec", "%\f\a\x051\x92\x01*\r\x14"},
{"crypto/internal/fips140/nistec/fiat", "%\x136\x92\x01"},
{"crypto/internal/fips140/pbkdf2", "\x03\x1d\x05\t\x06:\x15"},
{"crypto/internal/fips140/rsa", "\x03\x1d\x04\x01\x02\r\x01\x01\x026\x15nF"},
{"crypto/internal/fips140/sha256", "\x03\x1d\x1d\x01\x06*\x15}"},
{"crypto/internal/fips140/sha3", "\x03\x1d\x18\x05\x010\x92\x01K"},
{"crypto/internal/fips140/sha512", "\x03\x1d\x1d\x01\x06*\x15}"},
{"crypto/internal/fips140/ssh", "%^"},
{"crypto/internal/fips140/subtle", "#\x1a\xc3\x01"},
{"crypto/internal/fips140/tls12", "\x03\x1d\x05\t\x06\x028\x15"},
{"crypto/internal/fips140/tls13", "\x03\x1d\x05\b\a\t1\x15"},
{"crypto/internal/fips140cache", "\xaa\x02\r&"},
{"crypto/internal/constanttime", ""},
{"crypto/internal/cryptotest", "\x03\r\n\b%\x0e\x19\x06\x12\x12 \x04\x06\t\x18\x01\x11\x11\x1b\x01\a\x05\b\x03\x05\v"},
{"crypto/internal/entropy", "I"},
{"crypto/internal/entropy/v1.0.0", "B/\x93\x018\x13"},
{"crypto/internal/fips140", "A0\xbd\x01\v\x16"},
{"crypto/internal/fips140/aes", "\x03\x1f\x03\x02\x13\x05\x01\x01\x06*\x93\x014"},
{"crypto/internal/fips140/aes/gcm", "\"\x01\x02\x02\x02\x11\x05\x01\a*\x90\x01"},
{"crypto/internal/fips140/alias", "\xcf\x02"},
{"crypto/internal/fips140/bigmod", "'\x18\x01\a*\x93\x01"},
{"crypto/internal/fips140/check", "\"\x0e\x06\t\x02\xb4\x01Z"},
{"crypto/internal/fips140/check/checktest", "'\x87\x02!"},
{"crypto/internal/fips140/drbg", "\x03\x1e\x01\x01\x04\x13\x05\t\x01(\x84\x01\x0f7\x01"},
{"crypto/internal/fips140/ecdh", "\x03\x1f\x05\x02\t\r2\x84\x01\x0f7"},
{"crypto/internal/fips140/ecdsa", "\x03\x1f\x04\x01\x02\a\x02\x069\x15oF"},
{"crypto/internal/fips140/ed25519", "\x03\x1f\x05\x02\x04\v9\xc7\x01\x03"},
{"crypto/internal/fips140/edwards25519", "\x1e\t\a\x112\x93\x017"},
{"crypto/internal/fips140/edwards25519/field", "'\x13\x052\x93\x01"},
{"crypto/internal/fips140/hkdf", "\x03\x1f\x05\t\x06;\x15"},
{"crypto/internal/fips140/hmac", "\x03\x1f\x14\x01\x019\x15"},
{"crypto/internal/fips140/mlkem", "\x03\x1f\x05\x02\x0e\x03\x052\xca\x01"},
{"crypto/internal/fips140/nistec", "\x1e\t\f\f2\x93\x01*\r\x14"},
{"crypto/internal/fips140/nistec/fiat", "'\x137\x93\x01"},
{"crypto/internal/fips140/pbkdf2", "\x03\x1f\x05\t\x06;\x15"},
{"crypto/internal/fips140/rsa", "\x03\x1b\x04\x04\x01\x02\r\x01\x01\x027\x15oF"},
{"crypto/internal/fips140/sha256", "\x03\x1f\x1d\x01\a*\x15~"},
{"crypto/internal/fips140/sha3", "\x03\x1f\x18\x05\x011\x93\x01K"},
{"crypto/internal/fips140/sha512", "\x03\x1f\x1d\x01\a*\x15~"},
{"crypto/internal/fips140/ssh", "'_"},
{"crypto/internal/fips140/subtle", "\x1e\a\x1a\xc5\x01"},
{"crypto/internal/fips140/tls12", "\x03\x1f\x05\t\x06\x029\x15"},
{"crypto/internal/fips140/tls13", "\x03\x1f\x05\b\a\t2\x15"},
{"crypto/internal/fips140cache", "\xae\x02\r&"},
{"crypto/internal/fips140deps", ""},
{"crypto/internal/fips140deps/byteorder", "\x99\x01"},
{"crypto/internal/fips140deps/cpu", "\xae\x01\a"},
{"crypto/internal/fips140deps/godebug", "\xb6\x01"},
{"crypto/internal/fips140hash", "5\x1b3\xc8\x01"},
{"crypto/internal/fips140only", "'\r\x01\x01M3;"},
{"crypto/internal/fips140deps/byteorder", "\x9c\x01"},
{"crypto/internal/fips140deps/cpu", "\xb1\x01\a"},
{"crypto/internal/fips140deps/godebug", "\xb9\x01"},
{"crypto/internal/fips140deps/time", "\xc9\x02"},
{"crypto/internal/fips140hash", "7\x1c3\xc9\x01"},
{"crypto/internal/fips140only", ")\r\x01\x01N3<"},
{"crypto/internal/fips140test", ""},
{"crypto/internal/hpke", "\x0e\x01\x01\x03\x053#+gM"},
{"crypto/internal/impl", "\xb5\x02"},
{"crypto/internal/randutil", "\xf1\x01\x12"},
{"crypto/internal/sysrand", "nn! \r\r\x01\x01\f\x06"},
{"crypto/internal/sysrand/internal/seccomp", "n"},
{"crypto/md5", "\x0e3-\x15\x16g"},
{"crypto/mlkem", "/"},
{"crypto/pbkdf2", "2\x0e\x01-\x15"},
{"crypto/rand", "\x1a\x06\a\x1a\x04\x01(\x83\x01\rM"},
{"crypto/rc4", "#\x1e-\xc6\x01"},
{"crypto/rsa", "\x0e\f\x01\t\x0f\r\x01\x04\x06\a\x1c\x03\x123;\f\x01"},
{"crypto/sha1", "\x0e\f'\x03*\x15\x16\x15R"},
{"crypto/sha256", "\x0e\f\x1aO"},
{"crypto/sha3", "\x0e'N\xc8\x01"},
{"crypto/sha512", "\x0e\f\x1cM"},
{"crypto/subtle", "8\x9b\x01W"},
{"crypto/tls", "\x03\b\x02\x01\x01\x01\x01\x02\x01\x01\x01\x02\x01\x01\a\x01\r\n\x01\t\x05\x03\x01\x01\x01\x01\x02\x01\x02\x01\x17\x02\x03\x12\x16\x15\b;\x16\x16\r\b\x01\x01\x01\x02\x01\r\x06\x02\x01\x0f"},
{"crypto/tls/internal/fips140tls", "\x17\xa1\x02"},
{"crypto/x509", "\x03\v\x01\x01\x01\x01\x01\x01\x01\x012\x05\x01\x01\x02\x05\x0e\x06\x02\x02\x03E\x038\x01\x02\b\x01\x01\x02\a\x10\x05\x01\x06\x02\x05\n\x01\x02\x0e\x02\x01\x01\x02\x03\x01"},
{"crypto/x509/pkix", "d\x06\a\x8d\x01G"},
{"database/sql", "\x03\nK\x16\x03\x80\x01\v\a\"\x05\b\x02\x03\x01\r\x02\x02\x02"},
{"database/sql/driver", "\ra\x03\xb4\x01\x0f\x11"},
{"debug/buildinfo", "\x03X\x02\x01\x01\b\a\x03e\x19\x02\x01+\x0f\x1f"},
{"debug/dwarf", "\x03d\a\x03\x80\x011\x11\x01\x01"},
{"debug/elf", "\x03\x06Q\r\a\x03e\x1a\x01,\x17\x01\x16"},
{"debug/gosym", "\x03d\n\xc2\x01\x01\x01\x02"},
{"debug/macho", "\x03\x06Q\r\ne\x1b,\x17\x01"},
{"debug/pe", "\x03\x06Q\r\a\x03e\x1b,\x17\x01\x16"},
{"debug/plan9obj", "g\a\x03e\x1b,"},
{"embed", "n*@\x19\x01S"},
{"crypto/internal/hpke", "\x0e\x01\x01\x03\x056#+hM"},
{"crypto/internal/impl", "\xb9\x02"},
{"crypto/internal/randutil", "\xf5\x01\x12"},
{"crypto/internal/sysrand", "qo! \r\r\x01\x01\f\x06"},
{"crypto/internal/sysrand/internal/seccomp", "q"},
{"crypto/md5", "\x0e6-\x15\x16h"},
{"crypto/mlkem", "1"},
{"crypto/pbkdf2", "4\x0f\x01-\x15"},
{"crypto/rand", "\x1a\b\a\x1b\x04\x01(\x84\x01\rM"},
{"crypto/rc4", "%\x1f-\xc7\x01"},
{"crypto/rsa", "\x0e\f\x01\v\x0f\x0e\x01\x04\x06\a\x1c\x03\x123<\f\x01"},
{"crypto/sha1", "\x0e\f*\x03*\x15\x16\x15S"},
{"crypto/sha256", "\x0e\f\x1cP"},
{"crypto/sha3", "\x0e)O\xc9\x01"},
{"crypto/sha512", "\x0e\f\x1eN"},
{"crypto/subtle", "\x1e\x1c\x9c\x01X"},
{"crypto/tls", "\x03\b\x02\x01\x01\x01\x01\x02\x01\x01\x01\x02\x01\x01\t\x01\r\n\x01\n\x05\x03\x01\x01\x01\x01\x02\x01\x02\x01\x17\x02\x03\x12\x16\x15\b<\x16\x16\r\b\x01\x01\x01\x02\x01\r\x06\x02\x01\x0f"},
{"crypto/tls/internal/fips140tls", "\x17\xa5\x02"},
{"crypto/x509", "\x03\v\x01\x01\x01\x01\x01\x01\x01\x015\x05\x01\x01\x02\x05\x0e\x06\x02\x02\x03E\x039\x01\x02\b\x01\x01\x02\a\x10\x05\x01\x06\x02\x05\b\x02\x01\x02\x0e\x02\x01\x01\x02\x03\x01"},
{"crypto/x509/pkix", "g\x06\a\x8e\x01G"},
{"database/sql", "\x03\nN\x16\x03\x81\x01\v\a\"\x05\b\x02\x03\x01\r\x02\x02\x02"},
{"database/sql/driver", "\rd\x03\xb5\x01\x0f\x11"},
{"debug/buildinfo", "\x03[\x02\x01\x01\b\a\x03e\x1a\x02\x01+\x0f\x1f"},
{"debug/dwarf", "\x03g\a\x03\x81\x011\x11\x01\x01"},
{"debug/elf", "\x03\x06T\r\a\x03e\x1b\x01\f \x17\x01\x16"},
{"debug/gosym", "\x03g\n\xc3\x01\x01\x01\x02"},
{"debug/macho", "\x03\x06T\r\ne\x1c,\x17\x01"},
{"debug/pe", "\x03\x06T\r\a\x03e\x1c,\x17\x01\x16"},
{"debug/plan9obj", "j\a\x03e\x1c,"},
{"embed", "q*A\x19\x01S"},
{"embed/internal/embedtest", ""},
{"encoding", ""},
{"encoding/ascii85", "\xf1\x01C"},
{"encoding/asn1", "\x03k\x03\x8c\x01\x01'\r\x02\x01\x10\x03\x01"},
{"encoding/base32", "\xf1\x01A\x02"},
{"encoding/base64", "\x99\x01XA\x02"},
{"encoding/binary", "n\x83\x01\f(\r\x05"},
{"encoding/csv", "\x02\x01k\x03\x80\x01D\x12\x02"},
{"encoding/gob", "\x02`\x05\a\x03e\x1b\v\x01\x03\x1d\b\x12\x01\x0f\x02"},
{"encoding/hex", "n\x03\x80\x01A\x03"},
{"encoding/json", "\x03\x01^\x04\b\x03\x80\x01\f(\r\x02\x01\x02\x10\x01\x01\x02"},
{"encoding/pem", "\x03c\b\x83\x01A\x03"},
{"encoding/xml", "\x02\x01_\f\x03\x80\x014\x05\n\x01\x02\x10\x02"},
{"errors", "\xca\x01\x81\x01"},
{"expvar", "kK?\b\v\x15\r\b\x02\x03\x01\x11"},
{"flag", "b\f\x03\x80\x01,\b\x05\b\x02\x01\x10"},
{"fmt", "nE>\f \b\r\x02\x03\x12"},
{"go/ast", "\x03\x01m\x0e\x01q\x03)\b\r\x02\x01"},
{"go/build", "\x02\x01k\x03\x01\x02\x02\a\x02\x01\x17\x1f\x04\x02\t\x19\x13\x01+\x01\x04\x01\a\b\x02\x01\x12\x02\x02"},
{"go/build/constraint", "n\xc6\x01\x01\x12\x02"},
{"go/constant", "q\x0f}\x01\x024\x01\x02\x12"},
{"go/doc", "\x04m\x01\x05\t>31\x10\x02\x01\x12\x02"},
{"go/doc/comment", "\x03n\xc1\x01\x01\x01\x01\x12\x02"},
{"go/format", "\x03n\x01\v\x01\x02qD"},
{"go/importer", "s\a\x01\x01\x04\x01p9"},
{"go/internal/gccgoimporter", "\x02\x01X\x13\x03\x04\v\x01n\x02,\x01\x05\x11\x01\f\b"},
{"go/internal/gcimporter", "\x02o\x0f\x010\x05\x0e-,\x15\x03\x02"},
{"go/internal/srcimporter", "q\x01\x01\n\x03\x01p,\x01\x05\x12\x02\x14"},
{"go/parser", "\x03k\x03\x01\x02\v\x01q\x01+\x06\x12"},
{"go/printer", "q\x01\x02\x03\tq\f \x15\x02\x01\x02\v\x05\x02"},
{"go/scanner", "\x03n\x0fq2\x10\x01\x13\x02"},
{"go/token", "\x04m\x83\x01>\x02\x03\x01\x0f\x02"},
{"go/types", "\x03\x01\x06d\x03\x01\x03\b\x03\x02\x15\x1f\x061\x04\x03\t \x06\a\b\x01\x01\x01\x02\x01\x0f\x02\x02"},
{"go/version", "\xbb\x01z"},
{"hash", "\xf1\x01"},
{"hash/adler32", "n\x15\x16"},
{"hash/crc32", "n\x15\x16\x15\x89\x01\x01\x13"},
{"hash/crc64", "n\x15\x16\x9e\x01"},
{"hash/fnv", "n\x15\x16g"},
{"hash/maphash", "\x83\x01\x11!\x03\x93\x01"},
{"html", "\xb5\x02\x02\x12"},
{"html/template", "\x03h\x06\x18-;\x01\n!\x05\x01\x02\x03\f\x01\x02\f\x01\x03\x02"},
{"image", "\x02l\x1ee\x0f4\x03\x01"},
{"encoding/ascii85", "\xf5\x01C"},
{"encoding/asn1", "\x03n\x03e(\x01'\r\x02\x01\x10\x03\x01"},
{"encoding/base32", "\xf5\x01A\x02"},
{"encoding/base64", "\x9c\x01YA\x02"},
{"encoding/binary", "q\x84\x01\f(\r\x05"},
{"encoding/csv", "\x02\x01n\x03\x81\x01D\x12\x02"},
{"encoding/gob", "\x02c\x05\a\x03e\x1c\v\x01\x03\x1d\b\x12\x01\x0f\x02"},
{"encoding/hex", "q\x03\x81\x01A\x03"},
{"encoding/json", "\x03\x01a\x04\b\x03\x81\x01\f(\r\x02\x01\x02\x10\x01\x01\x02"},
{"encoding/pem", "\x03f\b\x84\x01A\x03"},
{"encoding/xml", "\x02\x01b\f\x03\x81\x014\x05\n\x01\x02\x10\x02"},
{"errors", "\xcc\x01\x83\x01"},
{"expvar", "nK@\b\v\x15\r\b\x02\x03\x01\x11"},
{"flag", "e\f\x03\x81\x01,\b\x05\b\x02\x01\x10"},
{"fmt", "qE&\x19\f \b\r\x02\x03\x12"},
{"go/ast", "\x03\x01p\x0e\x01r\x03)\b\r\x02\x01\x12\x02"},
{"go/build", "\x02\x01n\x03\x01\x02\x02\a\x02\x01\x17\x1f\x04\x02\b\x1b\x13\x01+\x01\x04\x01\a\b\x02\x01\x12\x02\x02"},
{"go/build/constraint", "q\xc7\x01\x01\x12\x02"},
{"go/constant", "t\x0f~\x01\x024\x01\x02\x12"},
{"go/doc", "\x04p\x01\x05\t=51\x10\x02\x01\x12\x02"},
{"go/doc/comment", "\x03q\xc2\x01\x01\x01\x01\x12\x02"},
{"go/format", "\x03q\x01\v\x01\x02rD"},
{"go/importer", "v\a\x01\x01\x04\x01q9"},
{"go/internal/gccgoimporter", "\x02\x01[\x13\x03\x04\v\x01o\x02,\x01\x05\x11\x01\f\b"},
{"go/internal/gcimporter", "\x02r\x0f\x010\x05\r/,\x15\x03\x02"},
{"go/internal/srcimporter", "t\x01\x01\n\x03\x01q,\x01\x05\x12\x02\x14"},
{"go/parser", "\x03n\x03\x01\x02\v\x01r\x01+\x06\x12"},
{"go/printer", "t\x01\x02\x03\tr\f \x15\x02\x01\x02\v\x05\x02"},
{"go/scanner", "\x03q\x0fr2\x10\x01\x13\x02"},
{"go/token", "\x04p\x84\x01>\x02\x03\x01\x0f\x02"},
{"go/types", "\x03\x01\x06g\x03\x01\x03\b\x03\x024\x062\x04\x03\t \x06\a\b\x01\x01\x01\x02\x01\x0f\x02\x02"},
{"go/version", "\xbe\x01{"},
{"hash", "\xf5\x01"},
{"hash/adler32", "q\x15\x16"},
{"hash/crc32", "q\x15\x16\x15\x8a\x01\x01\x13"},
{"hash/crc64", "q\x15\x16\x9f\x01"},
{"hash/fnv", "q\x15\x16h"},
{"hash/maphash", "\x86\x01\x11<|"},
{"html", "\xb9\x02\x02\x12"},
{"html/template", "\x03k\x06\x18-<\x01\n!\x05\x01\x02\x03\f\x01\x02\f\x01\x03\x02"},
{"image", "\x02o\x1ef\x0f4\x03\x01"},
{"image/color", ""},
{"image/color/palette", "\x8c\x01"},
{"image/draw", "\x8b\x01\x01\x04"},
{"image/gif", "\x02\x01\x05f\x03\x1a\x01\x01\x01\vX"},
{"image/internal/imageutil", "\x8b\x01"},
{"image/jpeg", "\x02l\x1d\x01\x04a"},
{"image/png", "\x02\a^\n\x12\x02\x06\x01eC"},
{"index/suffixarray", "\x03d\a\x83\x01\f+\n\x01"},
{"internal/abi", "\xb5\x01\x96\x01"},
{"internal/asan", "\xcb\x02"},
{"internal/bisect", "\xaa\x02\r\x01"},
{"internal/buildcfg", "qGe\x06\x02\x05\n\x01"},
{"internal/bytealg", "\xae\x01\x9d\x01"},
{"image/color/palette", "\x8f\x01"},
{"image/draw", "\x8e\x01\x01\x04"},
{"image/gif", "\x02\x01\x05i\x03\x1a\x01\x01\x01\vY"},
{"image/internal/imageutil", "\x8e\x01"},
{"image/jpeg", "\x02o\x1d\x01\x04b"},
{"image/png", "\x02\aa\n\x12\x02\x06\x01fC"},
{"index/suffixarray", "\x03g\a\x84\x01\f+\n\x01"},
{"internal/abi", "\xb8\x01\x97\x01"},
{"internal/asan", "\xcf\x02"},
{"internal/bisect", "\xae\x02\r\x01"},
{"internal/buildcfg", "tGf\x06\x02\x05\n\x01"},
{"internal/bytealg", "\xb1\x01\x9e\x01"},
{"internal/byteorder", ""},
{"internal/cfg", ""},
{"internal/cgrouptest", "q[Q\x06\x0f\x02\x01\x04\x01"},
{"internal/chacha8rand", "\x99\x01\x15\a\x96\x01"},
{"internal/cgrouptest", "tZS\x06\x0f\x02\x01\x04\x01"},
{"internal/chacha8rand", "\x9c\x01\x15\a\x97\x01"},
{"internal/copyright", ""},
{"internal/coverage", ""},
{"internal/coverage/calloc", ""},
{"internal/coverage/cfile", "k\x06\x16\x17\x01\x02\x01\x01\x01\x01\x01\x01\x01#\x02$,\x06\a\n\x01\x03\r\x06"},
{"internal/coverage/cformat", "\x04m-\x04O\v6\x01\x02\r"},
{"internal/coverage/cmerge", "q-_"},
{"internal/coverage/decodecounter", "g\n-\v\x02F,\x17\x17"},
{"internal/coverage/decodemeta", "\x02e\n\x16\x17\v\x02F,"},
{"internal/coverage/encodecounter", "\x02e\n-\f\x01\x02D\v!\x15"},
{"internal/coverage/encodemeta", "\x02\x01d\n\x12\x04\x17\r\x02D,."},
{"internal/coverage/pods", "\x04m-\x7f\x06\x05\n\x02\x01"},
{"internal/coverage/rtcov", "\xcb\x02"},
{"internal/coverage/slicereader", "g\n\x80\x01Z"},
{"internal/coverage/slicewriter", "q\x80\x01"},
{"internal/coverage/stringtab", "q8\x04D"},
{"internal/coverage/cfile", "n\x06\x16\x17\x01\x02\x01\x01\x01\x01\x01\x01\x01\"\x02&,\x06\a\n\x01\x03\r\x06"},
{"internal/coverage/cformat", "\x04p-\x04P\v6\x01\x02\r"},
{"internal/coverage/cmerge", "t-`"},
{"internal/coverage/decodecounter", "j\n-\v\x02G,\x17\x17"},
{"internal/coverage/decodemeta", "\x02h\n\x16\x17\v\x02G,"},
{"internal/coverage/encodecounter", "\x02h\n-\f\x01\x02E\v!\x15"},
{"internal/coverage/encodemeta", "\x02\x01g\n\x12\x04\x17\r\x02E,."},
{"internal/coverage/pods", "\x04p-\x80\x01\x06\x05\n\x02\x01"},
{"internal/coverage/rtcov", "\xcf\x02"},
{"internal/coverage/slicereader", "j\n\x81\x01Z"},
{"internal/coverage/slicewriter", "t\x81\x01"},
{"internal/coverage/stringtab", "t8\x04E"},
{"internal/coverage/test", ""},
{"internal/coverage/uleb128", ""},
{"internal/cpu", "\xcb\x02"},
{"internal/dag", "\x04m\xc1\x01\x03"},
{"internal/diff", "\x03n\xc2\x01\x02"},
{"internal/exportdata", "\x02\x01k\x03\x02c\x1b,\x01\x05\x11\x01\x02"},
{"internal/filepathlite", "n*@\x1a@"},
{"internal/fmtsort", "\x04\xa1\x02\r"},
{"internal/fuzz", "\x03\nB\x18\x04\x03\x03\x01\v\x036;\f\x03\x1d\x01\x05\x02\x05\n\x01\x02\x01\x01\f\x04\x02"},
{"internal/cpu", "\xcf\x02"},
{"internal/dag", "\x04p\xc2\x01\x03"},
{"internal/diff", "\x03q\xc3\x01\x02"},
{"internal/exportdata", "\x02\x01n\x03\x02c\x1c,\x01\x05\x11\x01\x02"},
{"internal/filepathlite", "q*A\x1a@"},
{"internal/fmtsort", "\x04\xa5\x02\r"},
{"internal/fuzz", "\x03\nE\x18\x04\x03\x03\x01\v\x036<\f\x03\x1d\x01\x05\x02\x05\n\x01\x02\x01\x01\f\x04\x02"},
{"internal/goarch", ""},
{"internal/godebug", "\x96\x01!\x80\x01\x01\x13"},
{"internal/godebug", "\x99\x01!\x81\x01\x01\x13"},
{"internal/godebugs", ""},
{"internal/goexperiment", ""},
{"internal/goos", ""},
{"internal/goroot", "\x9d\x02\x01\x05\x12\x02"},
{"internal/goroot", "\xa1\x02\x01\x05\x12\x02"},
{"internal/gover", "\x04"},
{"internal/goversion", ""},
{"internal/itoa", ""},
{"internal/lazyregexp", "\x9d\x02\v\r\x02"},
{"internal/lazytemplate", "\xf1\x01,\x18\x02\f"},
{"internal/msan", "\xcb\x02"},
{"internal/lazyregexp", "\xa1\x02\v\r\x02"},
{"internal/lazytemplate", "\xf5\x01,\x18\x02\f"},
{"internal/msan", "\xcf\x02"},
{"internal/nettrace", ""},
{"internal/obscuretestdata", "f\x8b\x01,"},
{"internal/oserror", "n"},
{"internal/pkgbits", "\x03L\x18\a\x03\x04\vq\r\x1f\r\n\x01"},
{"internal/obscuretestdata", "i\x8c\x01,"},
{"internal/oserror", "q"},
{"internal/pkgbits", "\x03O\x18\a\x03\x04\vr\r\x1f\r\n\x01"},
{"internal/platform", ""},
{"internal/poll", "nO\x1f\x159\r\x01\x01\f\x06"},
{"internal/profile", "\x03\x04g\x03\x80\x017\v\x01\x01\x10"},
{"internal/poll", "qj\x05\x159\r\x01\x01\f\x06"},
{"internal/profile", "\x03\x04j\x03\x81\x017\n\x01\x01\x01\x10"},
{"internal/profilerecord", ""},
{"internal/race", "\x94\x01\xb7\x01"},
{"internal/reflectlite", "\x94\x01!9<!"},
{"internal/runtime/atomic", "\xb5\x01\x96\x01"},
{"internal/runtime/cgroup", "\x98\x01:\x02w"},
{"internal/runtime/exithook", "\xcb\x01\x80\x01"},
{"internal/runtime/gc", "\xb5\x01"},
{"internal/runtime/maps", "\x94\x01\x01 \v\t\a\x03x"},
{"internal/runtime/math", "\xb5\x01"},
{"internal/race", "\x97\x01\xb8\x01"},
{"internal/reflectlite", "\x97\x01!:<!"},
{"internal/runtime/atomic", "\xb8\x01\x97\x01"},
{"internal/runtime/cgroup", "\x9b\x01<\x04t"},
{"internal/runtime/exithook", "\xcd\x01\x82\x01"},
{"internal/runtime/gc", "\xb8\x01"},
{"internal/runtime/gc/internal/gen", "\n`\n\x17j\x04\v\x1d\b\x10\x02"},
{"internal/runtime/gc/scan", "\xb1\x01\a\x18\x06y"},
{"internal/runtime/maps", "\x97\x01\x01 \n\t\t\x02y"},
{"internal/runtime/math", "\xb8\x01"},
{"internal/runtime/startlinetest", ""},
{"internal/runtime/strconv", "\xd0\x01"},
{"internal/runtime/sys", "\xb5\x01\x04"},
{"internal/runtime/syscall", "\xb5\x01\x96\x01"},
{"internal/runtime/sys", "\xb8\x01\x04"},
{"internal/runtime/syscall/linux", "\xb8\x01\x97\x01"},
{"internal/runtime/wasitest", ""},
{"internal/saferio", "\xf1\x01Z"},
{"internal/singleflight", "\xb7\x02"},
{"internal/stringslite", "\x98\x01\xb3\x01"},
{"internal/sync", "\x94\x01!\x14o\x13"},
{"internal/synctest", "\x94\x01\xb7\x01"},
{"internal/syscall/execenv", "\xb9\x02"},
{"internal/syscall/unix", "\xaa\x02\x0e\x01\x12"},
{"internal/sysinfo", "\x02\x01\xab\x01C,\x18\x02"},
{"internal/saferio", "\xf5\x01Z"},
{"internal/singleflight", "\xbb\x02"},
{"internal/strconv", "\x84\x02K"},
{"internal/stringslite", "\x9b\x01\xb4\x01"},
{"internal/sync", "\x97\x01!\x13q\x13"},
{"internal/synctest", "\x97\x01\xb8\x01"},
{"internal/syscall/execenv", "\xbd\x02"},
{"internal/syscall/unix", "\xae\x02\x0e\x01\x12"},
{"internal/sysinfo", "\x02\x01\xae\x01D,\x18\x02"},
{"internal/syslist", ""},
{"internal/testenv", "\x03\na\x02\x01)\x1b\x10-+\x01\x05\a\n\x01\x02\x02\x01\v"},
{"internal/testhash", "\x03\x80\x01n\x118\v"},
{"internal/testlog", "\xb7\x02\x01\x13"},
{"internal/testpty", "n\x03\xac\x01"},
{"internal/trace", "\x02\x01\x01\x06]\a\x03t\x03\x03\x06\x03\t5\x01\x01\x01\x10\x06"},
{"internal/trace/internal/testgen", "\x03d\nr\x03\x02\x03\x011\v\r\x10"},
{"internal/trace/internal/tracev1", "\x03\x01c\a\x03z\x06\f5\x01"},
{"internal/trace/raw", "\x02e\nw\x03\x06C\x01\x12"},
{"internal/trace/testtrace", "\x02\x01k\x03r\x03\x05\x01\x057\n\x02\x01"},
{"internal/testenv", "\x03\nd\x02\x01)\x1b\x0f/+\x01\x05\a\n\x01\x02\x02\x01\v"},
{"internal/testhash", "\x03\x83\x01o\x118\v"},
{"internal/testlog", "\xbb\x02\x01\x13"},
{"internal/testpty", "q\x03\xad\x01"},
{"internal/trace", "\x02\x01\x01\x06`\a\x03u\x03\x03\x06\x03\t5\x01\x01\x01\x10\x06"},
{"internal/trace/internal/testgen", "\x03g\ns\x03\x02\x03\x011\v\r\x10"},
{"internal/trace/internal/tracev1", "\x03\x01f\a\x03{\x06\f5\x01"},
{"internal/trace/raw", "\x02h\nx\x03\x06C\x01\x12"},
{"internal/trace/testtrace", "\x02\x01n\x03o\x04\x03\x05\x01\x05,\v\x02\b\x02\x01\x05"},
{"internal/trace/tracev2", ""},
{"internal/trace/traceviewer", "\x02^\v\x06\x19=\x1c\a\a\x04\b\v\x15\x01\x05\a\n\x01\x02\x0e"},
{"internal/trace/traceviewer", "\x02a\v\x06\x19<\x1e\a\a\x04\b\v\x15\x01\x05\a\n\x01\x02\x0e"},
{"internal/trace/traceviewer/format", ""},
{"internal/trace/version", "qw\t"},
{"internal/txtar", "\x03n\xac\x01\x18"},
{"internal/types/errors", "\xb4\x02"},
{"internal/unsafeheader", "\xcb\x02"},
{"internal/xcoff", "Z\r\a\x03e\x1b,\x17\x01"},
{"internal/zstd", "g\a\x03\x80\x01\x0f"},
{"io", "n\xc9\x01"},
{"io/fs", "n*+.1\x10\x13\x04"},
{"io/ioutil", "\xf1\x01\x01+\x15\x03"},
{"iter", "\xc9\x01a!"},
{"log", "q\x80\x01\x05'\r\r\x01\r"},
{"internal/trace/version", "tx\t"},
{"internal/txtar", "\x03q\xad\x01\x18"},
{"internal/types/errors", "\xb8\x02"},
{"internal/unsafeheader", "\xcf\x02"},
{"internal/xcoff", "]\r\a\x03e\x1c,\x17\x01"},
{"internal/zstd", "j\a\x03\x81\x01\x0f"},
{"io", "q\xca\x01"},
{"io/fs", "q**01\x10\x13\x04"},
{"io/ioutil", "\xf5\x01\x01+\x15\x03"},
{"iter", "\xcb\x01c!"},
{"log", "t\x81\x01\x05'\r\r\x01\r"},
{"log/internal", ""},
{"log/slog", "\x03\nU\t\x03\x03\x80\x01\x04\x01\x02\x02\x03(\x05\b\x02\x01\x02\x01\r\x02\x02\x02"},
{"log/slog", "\x03\nX\t\x03\x03\x81\x01\x04\x01\x02\x02\x03(\x05\b\x02\x01\x02\x01\r\x02\x02\x02"},
{"log/slog/internal", ""},
{"log/slog/internal/benchmarks", "\ra\x03\x80\x01\x06\x03:\x11"},
{"log/slog/internal/buffer", "\xb7\x02"},
{"log/syslog", "n\x03\x84\x01\x12\x16\x18\x02\x0e"},
{"maps", "\xf4\x01W"},
{"math", "\xae\x01RK"},
{"math/big", "\x03k\x03(\x15C\f\x03\x020\x02\x01\x02\x14"},
{"math/big/internal/asmgen", "\x03\x01m\x8f\x012\x03"},
{"math/bits", "\xcb\x02"},
{"math/cmplx", "\xfd\x01\x03"},
{"math/rand", "\xb6\x01G:\x01\x13"},
{"math/rand/v2", "n+\x03a\x03K"},
{"mime", "\x02\x01c\b\x03\x80\x01\v!\x15\x03\x02\x10\x02"},
{"mime/multipart", "\x02\x01H#\x03E;\v\x01\a\x02\x15\x02\x06\x0f\x02\x01\x16"},
{"mime/quotedprintable", "\x02\x01n\x80\x01"},
{"net", "\x04\ta*\x1e\a\x04\x05\x11\x01\x04\x15\x01%\x06\r\b\x05\x01\x01\f\x06\a"},
{"net/http", "\x02\x01\x04\x04\x02>\b\x13\x01\a\x03E;\x01\x03\a\x01\x03\x02\x02\x01\x02\x06\x02\x01\x01\n\x01\x01\x05\x01\x02\x05\b\x01\x01\x01\x02\x01\r\x02\x02\x02\b\x01\x01\x01"},
{"net/http/cgi", "\x02Q\x1b\x03\x80\x01\x04\a\v\x01\x13\x01\x01\x01\x04\x01\x05\x02\b\x02\x01\x10\x0e"},
{"net/http/cookiejar", "\x04j\x03\x96\x01\x01\b\f\x16\x03\x02\x0e\x04"},
{"net/http/fcgi", "\x02\x01\nZ\a\x03\x80\x01\x16\x01\x01\x14\x18\x02\x0e"},
{"net/http/httptest", "\x02\x01\nF\x02\x1b\x01\x80\x01\x04\x12\x01\n\t\x02\x17\x01\x02\x0e\x0e"},
{"net/http/httptrace", "\rFnF\x14\n "},
{"net/http/httputil", "\x02\x01\na\x03\x80\x01\x04\x0f\x03\x01\x05\x02\x01\v\x01\x19\x02\x0e\x0e"},
{"net/http/internal", "\x02\x01k\x03\x80\x01"},
{"net/http/internal/ascii", "\xb5\x02\x12"},
{"net/http/internal/httpcommon", "\ra\x03\x9c\x01\x0e\x01\x17\x01\x01\x02\x1c\x02"},
{"net/http/internal/testcert", "\xb5\x02"},
{"net/http/pprof", "\x02\x01\nd\x18-\x11*\x04\x13\x14\x01\r\x04\x03\x01\x02\x01\x10"},
{"log/slog/internal/benchmarks", "\rd\x03\x81\x01\x06\x03:\x11"},
{"log/slog/internal/buffer", "\xbb\x02"},
{"log/syslog", "q\x03\x85\x01\x12\x16\x18\x02\x0e"},
{"maps", "\xf8\x01W"},
{"math", "\xb1\x01SK"},
{"math/big", "\x03n\x03(\x15D\f\x03\x020\x02\x01\x02\x14"},
{"math/big/internal/asmgen", "\x03\x01p\x90\x012\x03"},
{"math/bits", "\xcf\x02"},
{"math/cmplx", "\x81\x02\x03"},
{"math/rand", "\xb9\x01H:\x01\x13"},
{"math/rand/v2", "q+\x03b\x03K"},
{"mime", "\x02\x01f\b\x03\x81\x01\v!\x15\x03\x02\x10\x02"},
{"mime/multipart", "\x02\x01K#\x03E<\v\x01\a\x02\x15\x02\x06\x0f\x02\x01\x16"},
{"mime/quotedprintable", "\x02\x01q\x81\x01"},
{"net", "\x04\td*\x1e\n\x05\x12\x01\x01\x04\x15\x01%\x06\r\b\x05\x01\x01\f\x06\a"},
{"net/http", "\x02\x01\x03\x01\x04\x02A\b\x13\x01\a\x03E<\x01\x03\a\x01\x03\x02\x02\x01\x02\x06\x02\x01\x01\n\x01\x01\x05\x01\x02\x05\b\x01\x01\x01\x02\x01\r\x02\x02\x02\b\x01\x01\x01"},
{"net/http/cgi", "\x02T\x1b\x03\x81\x01\x04\a\v\x01\x13\x01\x01\x01\x04\x01\x05\x02\b\x02\x01\x10\x0e"},
{"net/http/cookiejar", "\x04m\x03\x97\x01\x01\b\f\x16\x03\x02\x0e\x04"},
{"net/http/fcgi", "\x02\x01\n]\a\x03\x81\x01\x16\x01\x01\x14\x18\x02\x0e"},
{"net/http/httptest", "\x02\x01\nI\x02\x1b\x01\x81\x01\x04\x12\x01\n\t\x02\x17\x01\x02\x0e\x0e"},
{"net/http/httptrace", "\rImH\x14\n "},
{"net/http/httputil", "\x02\x01\nd\x03\x81\x01\x04\x0f\x03\x01\x05\x02\x01\v\x01\x19\x02\x0e\x0e"},
{"net/http/internal", "\x02\x01n\x03\x81\x01"},
{"net/http/internal/ascii", "\xb9\x02\x12"},
{"net/http/internal/httpcommon", "\rd\x03\x9d\x01\x0e\x01\x17\x01\x01\x02\x1c\x02"},
{"net/http/internal/testcert", "\xb9\x02"},
{"net/http/pprof", "\x02\x01\ng\x18-\x02\x0e,\x04\x13\x14\x01\r\x04\x03\x01\x02\x01\x10"},
{"net/internal/cgotest", ""},
{"net/internal/socktest", "q\xc6\x01\x02"},
{"net/mail", "\x02l\x03\x80\x01\x04\x0f\x03\x14\x1a\x02\x0e\x04"},
{"net/netip", "\x04j*\x01$@\x034\x16"},
{"net/rpc", "\x02g\x05\x03\x0f\ng\x04\x12\x01\x1d\r\x03\x02"},
{"net/rpc/jsonrpc", "k\x03\x03\x80\x01\x16\x11\x1f"},
{"net/smtp", "\x19/\v\x13\b\x03\x80\x01\x16\x14\x1a"},
{"net/textproto", "\x02\x01k\x03\x80\x01\f\n-\x01\x02\x14"},
{"net/url", "n\x03\x8b\x01&\x10\x02\x01\x16"},
{"os", "n*\x01\x19\x03\b\t\x12\x03\x01\x05\x10\x018\b\x05\x01\x01\f\x06"},
{"os/exec", "\x03\naH%\x01\x15\x01+\x06\a\n\x01\x04\f"},
{"os/exec/internal/fdtest", "\xb9\x02"},
{"os/signal", "\r\x90\x02\x15\x05\x02"},
{"os/user", "\x02\x01k\x03\x80\x01,\r\n\x01\x02"},
{"path", "n*\xb1\x01"},
{"path/filepath", "n*\x1a@+\r\b\x03\x04\x10"},
{"plugin", "n"},
{"reflect", "n&\x04\x1d\b\f\x06\x04\x1b\x06\t-\n\x03\x10\x02\x02"},
{"net/internal/socktest", "t\xc7\x01\x02"},
{"net/mail", "\x02o\x03\x81\x01\x04\x0f\x03\x14\x1a\x02\x0e\x04"},
{"net/netip", "\x04m*\x01e\x034\x16"},
{"net/rpc", "\x02j\x05\x03\x0f\nh\x04\x12\x01\x1d\r\x03\x02"},
{"net/rpc/jsonrpc", "n\x03\x03\x81\x01\x16\x11\x1f"},
{"net/smtp", "\x192\v\x13\b\x03\x81\x01\x16\x14\x1a"},
{"net/textproto", "\x02\x01n\x03\x81\x01\f\n-\x01\x02\x14"},
{"net/url", "q\x03\xa7\x01\v\x10\x02\x01\x16"},
{"os", "q*\x01\x19\x03\x10\x13\x01\x03\x01\x05\x10\x018\b\x05\x01\x01\f\x06"},
{"os/exec", "\x03\ndH&\x01\x15\x01+\x06\a\n\x01\x04\f"},
{"os/exec/internal/fdtest", "\xbd\x02"},
{"os/signal", "\r\x94\x02\x15\x05\x02"},
{"os/user", "\x02\x01n\x03\x81\x01,\r\n\x01\x02"},
{"path", "q*\xb2\x01"},
{"path/filepath", "q*\x1aA+\r\b\x03\x04\x10"},
{"plugin", "q"},
{"reflect", "q&\x04\x1d\x13\b\x03\x05\x17\x06\t-\n\x03\x10\x02\x02"},
{"reflect/internal/example1", ""},
{"reflect/internal/example2", ""},
{"regexp", "\x03\xee\x018\t\x02\x01\x02\x10\x02"},
{"regexp/syntax", "\xb2\x02\x01\x01\x01\x02\x10\x02"},
{"runtime", "\x94\x01\x04\x01\x03\f\x06\a\x02\x01\x01\x0f\x03\x01\x01\x01\x01\x01\x02\x01\x01\x04\x10c"},
{"runtime/coverage", "\xa0\x01Q"},
{"runtime/debug", "qUW\r\b\x02\x01\x10\x06"},
{"runtime/metrics", "\xb7\x01F-!"},
{"runtime/pprof", "\x02\x01\x01\x03\x06Z\a\x03#4)\f \r\b\x01\x01\x01\x02\x02\t\x03\x06"},
{"runtime/race", "\xb0\x02"},
{"regexp", "\x03\xf2\x018\t\x02\x01\x02\x10\x02"},
{"regexp/syntax", "\xb6\x02\x01\x01\x01\x02\x10\x02"},
{"runtime", "\x97\x01\x04\x01\x03\f\x06\a\x02\x01\x01\x0e\x03\x01\x01\x01\x02\x01\x01\x02\x01\x04\x01\x10c"},
{"runtime/coverage", "\xa3\x01R"},
{"runtime/debug", "tTY\r\b\x02\x01\x10\x06"},
{"runtime/metrics", "\xba\x01G-!"},
{"runtime/pprof", "\x02\x01\x01\x03\x06]\a\x03#$\x0f+\f \r\b\x01\x01\x01\x02\x02\t\x03\x06"},
{"runtime/race", "\xb4\x02"},
{"runtime/race/internal/amd64v1", ""},
{"runtime/trace", "\ra\x03w\t9\b\x05\x01\r\x06"},
{"slices", "\x04\xf0\x01\fK"},
{"sort", "\xca\x0162"},
{"strconv", "n*@%\x03I"},
{"strings", "n&\x04@\x19\x03\f7\x10\x02\x02"},
{"runtime/trace", "\rd\x03x\t9\b\x05\x01\r\x06"},
{"slices", "\x04\xf4\x01\fK"},
{"sort", "\xcc\x0182"},
{"strconv", "q*@\x01q"},
{"strings", "q&\x04A\x19\x03\f7\x10\x02\x02"},
{"structs", ""},
{"sync", "\xc9\x01\x10\x01P\x0e\x13"},
{"sync/atomic", "\xcb\x02"},
{"syscall", "n'\x03\x01\x1c\b\x03\x03\x06\vV\b\x05\x01\x13"},
{"testing", "\x03\na\x02\x01X\x14\x14\f\x05\x1b\x06\x02\x05\x02\x05\x01\x02\x01\x02\x01\r\x02\x02\x02"},
{"testing/fstest", "n\x03\x80\x01\x01\n&\x10\x03\b\b"},
{"testing/internal/testdeps", "\x02\v\xa7\x01-\x10,\x03\x05\x03\x06\a\x02\x0e"},
{"testing/iotest", "\x03k\x03\x80\x01\x04"},
{"testing/quick", "p\x01\x8c\x01\x05#\x10\x10"},
{"testing/slogtest", "\ra\x03\x86\x01.\x05\x10\v"},
{"testing/synctest", "\xda\x01`\x11"},
{"text/scanner", "\x03n\x80\x01,*\x02"},
{"text/tabwriter", "q\x80\x01X"},
{"text/template", "n\x03B>\x01\n \x01\x05\x01\x02\x05\v\x02\r\x03\x02"},
{"text/template/parse", "\x03n\xb9\x01\n\x01\x12\x02"},
{"time", "n*\x1e\"(*\r\x02\x12"},
{"time/tzdata", "n\xcb\x01\x12"},
{"sync", "\xcb\x01\x12\x01P\x0e\x13"},
{"sync/atomic", "\xcf\x02"},
{"syscall", "q'\x03\x01\x1c\n\x03\x06\f\x04S\b\x05\x01\x13"},
{"testing", "\x03\nd\x02\x01W\x16\x14\f\x05\x1b\x06\x02\x05\x02\x05\x01\x02\x01\x02\x01\r\x02\x04"},
{"testing/fstest", "q\x03\x81\x01\x01\n&\x10\x03\b\b"},
{"testing/internal/testdeps", "\x02\v\xaa\x01.\x10,\x03\x05\x03\x06\a\x02\x0e"},
{"testing/iotest", "\x03n\x03\x81\x01\x04"},
{"testing/quick", "s\x01\x8d\x01\x05#\x10\x10"},
{"testing/slogtest", "\rd\x03\x87\x01.\x05\x10\v"},
{"testing/synctest", "\xde\x01`\x11"},
{"text/scanner", "\x03q\x81\x01,*\x02"},
{"text/tabwriter", "t\x81\x01X"},
{"text/template", "q\x03B?\x01\n \x01\x05\x01\x02\x05\v\x02\r\x03\x02"},
{"text/template/parse", "\x03q\xba\x01\n\x01\x12\x02"},
{"time", "q*\x1e#(*\r\x02\x12"},
{"time/tzdata", "q\xcc\x01\x12"},
{"unicode", ""},
{"unicode/utf16", ""},
{"unicode/utf8", ""},
{"unique", "\x94\x01!#\x01Q\r\x01\x13\x12"},
{"unique", "\x97\x01!$\x01Q\r\x01\x13\x12"},
{"unsafe", ""},
{"vendor/golang.org/x/crypto/chacha20", "\x10W\a\x92\x01*&"},
{"vendor/golang.org/x/crypto/chacha20poly1305", "\x10W\a\xde\x01\x04\x01\a"},
{"vendor/golang.org/x/crypto/cryptobyte", "d\n\x03\x8d\x01' \n"},
{"vendor/golang.org/x/crypto/chacha20", "\x10Z\a\x93\x01*&"},
{"vendor/golang.org/x/crypto/chacha20poly1305", "\x10Z\a\xdf\x01\x04\x01\a"},
{"vendor/golang.org/x/crypto/cryptobyte", "g\n\x03\x8e\x01' \n"},
{"vendor/golang.org/x/crypto/cryptobyte/asn1", ""},
{"vendor/golang.org/x/crypto/internal/alias", "\xcb\x02"},
{"vendor/golang.org/x/crypto/internal/poly1305", "R\x15\x99\x01"},
{"vendor/golang.org/x/net/dns/dnsmessage", "n"},
{"vendor/golang.org/x/net/http/httpguts", "\x87\x02\x14\x1a\x14\r"},
{"vendor/golang.org/x/net/http/httpproxy", "n\x03\x96\x01\x10\x05\x01\x18\x14\r"},
{"vendor/golang.org/x/net/http2/hpack", "\x03k\x03\x80\x01F"},
{"vendor/golang.org/x/net/idna", "q\x8c\x018\x14\x10\x02\x01"},
{"vendor/golang.org/x/net/nettest", "\x03d\a\x03\x80\x01\x11\x05\x16\x01\f\n\x01\x02\x02\x01\v"},
{"vendor/golang.org/x/sys/cpu", "\x9d\x02\r\n\x01\x16"},
{"vendor/golang.org/x/text/secure/bidirule", "n\xdb\x01\x11\x01"},
{"vendor/golang.org/x/text/transform", "\x03k\x83\x01X"},
{"vendor/golang.org/x/text/unicode/bidi", "\x03\bf\x84\x01>\x16"},
{"vendor/golang.org/x/text/unicode/norm", "g\n\x80\x01F\x12\x11"},
{"weak", "\x94\x01\x96\x01!"},
{"vendor/golang.org/x/crypto/internal/alias", "\xcf\x02"},
{"vendor/golang.org/x/crypto/internal/poly1305", "U\x15\x9a\x01"},
{"vendor/golang.org/x/net/dns/dnsmessage", "q"},
{"vendor/golang.org/x/net/http/httpguts", "\x8b\x02\x14\x1a\x14\r"},
{"vendor/golang.org/x/net/http/httpproxy", "q\x03\x97\x01\x10\x05\x01\x18\x14\r"},
{"vendor/golang.org/x/net/http2/hpack", "\x03n\x03\x81\x01F"},
{"vendor/golang.org/x/net/idna", "t\x8d\x018\x14\x10\x02\x01"},
{"vendor/golang.org/x/net/nettest", "\x03g\a\x03\x81\x01\x11\x05\x16\x01\f\n\x01\x02\x02\x01\v"},
{"vendor/golang.org/x/sys/cpu", "\xa1\x02\r\n\x01\x16"},
{"vendor/golang.org/x/text/secure/bidirule", "q\xdc\x01\x11\x01"},
{"vendor/golang.org/x/text/transform", "\x03n\x84\x01X"},
{"vendor/golang.org/x/text/unicode/bidi", "\x03\bi\x85\x01>\x16"},
{"vendor/golang.org/x/text/unicode/norm", "j\n\x81\x01F\x12\x11"},
{"weak", "\x97\x01\x97\x01!"},
}
// bootstrap is the list of bootstrap packages extracted from cmd/dist.
var bootstrap = map[string]bool{
"cmp": true,
"cmd/asm": true,
"cmd/asm/internal/arch": true,
"cmd/asm/internal/asm": true,
"cmd/asm/internal/flags": true,
"cmd/asm/internal/lex": true,
"cmd/cgo": true,
"cmd/compile": true,
"cmd/compile/internal/abi": true,
"cmd/compile/internal/abt": true,
"cmd/compile/internal/amd64": true,
"cmd/compile/internal/arm": true,
"cmd/compile/internal/arm64": true,
"cmd/compile/internal/base": true,
"cmd/compile/internal/bitvec": true,
"cmd/compile/internal/compare": true,
"cmd/compile/internal/coverage": true,
"cmd/compile/internal/deadlocals": true,
"cmd/compile/internal/devirtualize": true,
"cmd/compile/internal/dwarfgen": true,
"cmd/compile/internal/escape": true,
"cmd/compile/internal/gc": true,
"cmd/compile/internal/importer": true,
"cmd/compile/internal/inline": true,
"cmd/compile/internal/inline/inlheur": true,
"cmd/compile/internal/inline/interleaved": true,
"cmd/compile/internal/ir": true,
"cmd/compile/internal/liveness": true,
"cmd/compile/internal/logopt": true,
"cmd/compile/internal/loong64": true,
"cmd/compile/internal/loopvar": true,
"cmd/compile/internal/mips": true,
"cmd/compile/internal/mips64": true,
"cmd/compile/internal/noder": true,
"cmd/compile/internal/objw": true,
"cmd/compile/internal/pgoir": true,
"cmd/compile/internal/pkginit": true,
"cmd/compile/internal/ppc64": true,
"cmd/compile/internal/rangefunc": true,
"cmd/compile/internal/reflectdata": true,
"cmd/compile/internal/riscv64": true,
"cmd/compile/internal/rttype": true,
"cmd/compile/internal/s390x": true,
"cmd/compile/internal/ssa": true,
"cmd/compile/internal/ssagen": true,
"cmd/compile/internal/staticdata": true,
"cmd/compile/internal/staticinit": true,
"cmd/compile/internal/syntax": true,
"cmd/compile/internal/test": true,
"cmd/compile/internal/typebits": true,
"cmd/compile/internal/typecheck": true,
"cmd/compile/internal/types": true,
"cmd/compile/internal/types2": true,
"cmd/compile/internal/walk": true,
"cmd/compile/internal/wasm": true,
"cmd/compile/internal/x86": true,
"cmd/internal/archive": true,
"cmd/internal/bio": true,
"cmd/internal/codesign": true,
"cmd/internal/dwarf": true,
"cmd/internal/edit": true,
"cmd/internal/gcprog": true,
"cmd/internal/goobj": true,
"cmd/internal/hash": true,
"cmd/internal/macho": true,
"cmd/internal/obj": true,
"cmd/internal/obj/arm": true,
"cmd/internal/obj/arm64": true,
"cmd/internal/obj/loong64": true,
"cmd/internal/obj/mips": true,
"cmd/internal/obj/ppc64": true,
"cmd/internal/obj/riscv": true,
"cmd/internal/obj/s390x": true,
"cmd/internal/obj/wasm": true,
"cmd/internal/obj/x86": true,
"cmd/internal/objabi": true,
"cmd/internal/par": true,
"cmd/internal/pgo": true,
"cmd/internal/pkgpath": true,
"cmd/internal/quoted": true,
"cmd/internal/src": true,
"cmd/internal/sys": true,
"cmd/internal/telemetry": true,
"cmd/internal/telemetry/counter": true,
"cmd/link": true,
"cmd/link/internal/amd64": true,
"cmd/link/internal/arm": true,
"cmd/link/internal/arm64": true,
"cmd/link/internal/benchmark": true,
"cmd/link/internal/dwtest": true,
"cmd/link/internal/ld": true,
"cmd/link/internal/loadelf": true,
"cmd/link/internal/loader": true,
"cmd/link/internal/loadmacho": true,
"cmd/link/internal/loadpe": true,
"cmd/link/internal/loadxcoff": true,
"cmd/link/internal/loong64": true,
"cmd/link/internal/mips": true,
"cmd/link/internal/mips64": true,
"cmd/link/internal/ppc64": true,
"cmd/link/internal/riscv64": true,
"cmd/link/internal/s390x": true,
"cmd/link/internal/sym": true,
"cmd/link/internal/wasm": true,
"cmd/link/internal/x86": true,
"compress/flate": true,
"compress/zlib": true,
"container/heap": true,
"debug/dwarf": true,
"debug/elf": true,
"debug/macho": true,
"debug/pe": true,
"go/build/constraint": true,
"go/constant": true,
"go/version": true,
"internal/abi": true,
"internal/coverage": true,
"cmd/internal/cov/covcmd": true,
"internal/bisect": true,
"internal/buildcfg": true,
"internal/exportdata": true,
"internal/goarch": true,
"internal/godebugs": true,
"internal/goexperiment": true,
"internal/goroot": true,
"internal/gover": true,
"internal/goversion": true,
"internal/lazyregexp": true,
"internal/pkgbits": true,
"internal/platform": true,
"internal/profile": true,
"internal/race": true,
"internal/runtime/gc": true,
"internal/saferio": true,
"internal/syscall/unix": true,
"internal/types/errors": true,
"internal/unsafeheader": true,
"internal/xcoff": true,
"internal/zstd": true,
"math/bits": true,
"sort": true,
}
// BootstrapVersion is the minor version of Go used during toolchain
// bootstrapping. Packages for which [IsBootstrapPackage] must not use
// features of Go newer than this version.
const BootstrapVersion = Version(24) // go1.24.6
+8
View File
@@ -87,3 +87,11 @@ func find(pkg string) (int, bool) {
return strings.Compare(p.name, n)
})
}
// IsBootstrapPackage reports whether pkg is one of the low-level
// packages in the Go distribution that must compile with the older
// language version specified by [BootstrapVersion] during toolchain
// bootstrapping; see golang.org/s/go15bootstrap.
func IsBootstrapPackage(pkg string) bool {
return bootstrap[pkg]
}
+37 -4
View File
@@ -225,6 +225,7 @@ var PackageSymbols = map[string][]Symbol{
{"(*Buffer).Grow", Method, 1, ""},
{"(*Buffer).Len", Method, 0, ""},
{"(*Buffer).Next", Method, 0, ""},
{"(*Buffer).Peek", Method, 26, ""},
{"(*Buffer).Read", Method, 0, ""},
{"(*Buffer).ReadByte", Method, 0, ""},
{"(*Buffer).ReadBytes", Method, 0, ""},
@@ -1628,6 +1629,7 @@ var PackageSymbols = map[string][]Symbol{
{"ResultNoRows", Var, 0, ""},
{"Rows", Type, 0, ""},
{"RowsAffected", Type, 0, ""},
{"RowsColumnScanner", Type, 26, ""},
{"RowsColumnTypeDatabaseTypeName", Type, 8, ""},
{"RowsColumnTypeLength", Type, 8, ""},
{"RowsColumnTypeNullable", Type, 8, ""},
@@ -4953,6 +4955,7 @@ var PackageSymbols = map[string][]Symbol{
},
"errors": {
{"As", Func, 13, "func(err error, target any) bool"},
{"AsType", Func, 26, "func[E error](err error) (E, bool)"},
{"ErrUnsupported", Var, 21, ""},
{"Is", Func, 13, "func(err error, target error) bool"},
{"Join", Func, 20, "func(errs ...error) error"},
@@ -5090,7 +5093,7 @@ var PackageSymbols = map[string][]Symbol{
{"Append", Func, 19, "func(b []byte, a ...any) []byte"},
{"Appendf", Func, 19, "func(b []byte, format string, a ...any) []byte"},
{"Appendln", Func, 19, "func(b []byte, a ...any) []byte"},
{"Errorf", Func, 0, "func(format string, a ...any) error"},
{"Errorf", Func, 0, "func(format string, a ...any) (err error)"},
{"FormatString", Func, 20, "func(state State, verb rune) string"},
{"Formatter", Type, 0, ""},
{"Fprint", Func, 0, "func(w io.Writer, a ...any) (n int, err error)"},
@@ -5155,6 +5158,9 @@ var PackageSymbols = map[string][]Symbol{
{"(*DeclStmt).Pos", Method, 0, ""},
{"(*DeferStmt).End", Method, 0, ""},
{"(*DeferStmt).Pos", Method, 0, ""},
{"(*Directive).End", Method, 26, ""},
{"(*Directive).ParseArgs", Method, 26, ""},
{"(*Directive).Pos", Method, 26, ""},
{"(*Ellipsis).End", Method, 0, ""},
{"(*Ellipsis).Pos", Method, 0, ""},
{"(*EmptyStmt).End", Method, 0, ""},
@@ -5320,6 +5326,15 @@ var PackageSymbols = map[string][]Symbol{
{"DeferStmt", Type, 0, ""},
{"DeferStmt.Call", Field, 0, ""},
{"DeferStmt.Defer", Field, 0, ""},
{"Directive", Type, 26, ""},
{"Directive.Args", Field, 26, ""},
{"Directive.ArgsPos", Field, 26, ""},
{"Directive.Name", Field, 26, ""},
{"Directive.Slash", Field, 26, ""},
{"Directive.Tool", Field, 26, ""},
{"DirectiveArg", Type, 26, ""},
{"DirectiveArg.Arg", Field, 26, ""},
{"DirectiveArg.Pos", Field, 26, ""},
{"Ellipsis", Type, 0, ""},
{"Ellipsis.Ellipsis", Field, 0, ""},
{"Ellipsis.Elt", Field, 0, ""},
@@ -5469,6 +5484,7 @@ var PackageSymbols = map[string][]Symbol{
{"ParenExpr.Lparen", Field, 0, ""},
{"ParenExpr.Rparen", Field, 0, ""},
{"ParenExpr.X", Field, 0, ""},
{"ParseDirective", Func, 26, "func(pos token.Pos, c string) (Directive, bool)"},
{"Pkg", Const, 0, ""},
{"Preorder", Func, 23, "func(root Node) iter.Seq[Node]"},
{"PreorderStack", Func, 25, "func(root Node, stack []Node, f func(n Node, stack []Node) bool)"},
@@ -7271,6 +7287,10 @@ var PackageSymbols = map[string][]Symbol{
{"(*Logger).WarnContext", Method, 21, ""},
{"(*Logger).With", Method, 21, ""},
{"(*Logger).WithGroup", Method, 21, ""},
{"(*MultiHandler).Enabled", Method, 26, ""},
{"(*MultiHandler).Handle", Method, 26, ""},
{"(*MultiHandler).WithAttrs", Method, 26, ""},
{"(*MultiHandler).WithGroup", Method, 26, ""},
{"(*Record).Add", Method, 21, ""},
{"(*Record).AddAttrs", Method, 21, ""},
{"(*TextHandler).Enabled", Method, 21, ""},
@@ -7358,9 +7378,11 @@ var PackageSymbols = map[string][]Symbol{
{"LogValuer", Type, 21, ""},
{"Logger", Type, 21, ""},
{"MessageKey", Const, 21, ""},
{"MultiHandler", Type, 26, ""},
{"New", Func, 21, "func(h Handler) *Logger"},
{"NewJSONHandler", Func, 21, "func(w io.Writer, opts *HandlerOptions) *JSONHandler"},
{"NewLogLogger", Func, 21, "func(h Handler, level Level) *log.Logger"},
{"NewMultiHandler", Func, 26, "func(handlers ...Handler) *MultiHandler"},
{"NewRecord", Func, 21, "func(t time.Time, level Level, msg string, pc uintptr) Record"},
{"NewTextHandler", Func, 21, "func(w io.Writer, opts *HandlerOptions) *TextHandler"},
{"Record", Type, 21, ""},
@@ -7515,7 +7537,7 @@ var PackageSymbols = map[string][]Symbol{
{"MinInt64", Const, 0, ""},
{"MinInt8", Const, 0, ""},
{"Mod", Func, 0, "func(x float64, y float64) float64"},
{"Modf", Func, 0, "func(f float64) (int float64, frac float64)"},
{"Modf", Func, 0, "func(f float64) (integer float64, fractional float64)"},
{"NaN", Func, 0, "func() float64"},
{"Nextafter", Func, 0, "func(x float64, y float64) (r float64)"},
{"Nextafter32", Func, 4, "func(x float32, y float32) (r float32)"},
@@ -7972,6 +7994,10 @@ var PackageSymbols = map[string][]Symbol{
{"(*DNSError).Unwrap", Method, 23, ""},
{"(*Dialer).Dial", Method, 1, ""},
{"(*Dialer).DialContext", Method, 7, ""},
{"(*Dialer).DialIP", Method, 26, ""},
{"(*Dialer).DialTCP", Method, 26, ""},
{"(*Dialer).DialUDP", Method, 26, ""},
{"(*Dialer).DialUnix", Method, 26, ""},
{"(*Dialer).MultipathTCP", Method, 21, ""},
{"(*Dialer).SetMultipathTCP", Method, 21, ""},
{"(*IP).UnmarshalText", Method, 2, ""},
@@ -8457,6 +8483,7 @@ var PackageSymbols = map[string][]Symbol{
{"HTTP2Config.PermitProhibitedCipherSuites", Field, 24, ""},
{"HTTP2Config.PingTimeout", Field, 24, ""},
{"HTTP2Config.SendPingTimeout", Field, 24, ""},
{"HTTP2Config.StrictMaxConcurrentRequests", Field, 26, ""},
{"HTTP2Config.WriteByteTimeout", Field, 24, ""},
{"Handle", Func, 0, "func(pattern string, handler Handler)"},
{"HandleFunc", Func, 0, "func(pattern string, handler func(ResponseWriter, *Request))"},
@@ -8904,6 +8931,7 @@ var PackageSymbols = map[string][]Symbol{
{"(Prefix).AppendText", Method, 24, ""},
{"(Prefix).AppendTo", Method, 18, ""},
{"(Prefix).Bits", Method, 18, ""},
{"(Prefix).Compare", Method, 26, ""},
{"(Prefix).Contains", Method, 18, ""},
{"(Prefix).IsSingleIP", Method, 18, ""},
{"(Prefix).IsValid", Method, 18, ""},
@@ -9177,6 +9205,7 @@ var PackageSymbols = map[string][]Symbol{
{"(*Process).Release", Method, 0, ""},
{"(*Process).Signal", Method, 0, ""},
{"(*Process).Wait", Method, 0, ""},
{"(*Process).WithHandle", Method, 26, ""},
{"(*ProcessState).ExitCode", Method, 12, ""},
{"(*ProcessState).Exited", Method, 0, ""},
{"(*ProcessState).Pid", Method, 0, ""},
@@ -9234,6 +9263,7 @@ var PackageSymbols = map[string][]Symbol{
{"ErrExist", Var, 0, ""},
{"ErrInvalid", Var, 0, ""},
{"ErrNoDeadline", Var, 10, ""},
{"ErrNoHandle", Var, 26, ""},
{"ErrNotExist", Var, 0, ""},
{"ErrPermission", Var, 0, ""},
{"ErrProcessDone", Var, 16, ""},
@@ -9461,7 +9491,7 @@ var PackageSymbols = map[string][]Symbol{
{"ListSeparator", Const, 0, ""},
{"Localize", Func, 23, "func(path string) (string, error)"},
{"Match", Func, 0, "func(pattern string, name string) (matched bool, err error)"},
{"Rel", Func, 0, "func(basepath string, targpath string) (string, error)"},
{"Rel", Func, 0, "func(basePath string, targPath string) (string, error)"},
{"Separator", Const, 0, ""},
{"SkipAll", Var, 20, ""},
{"SkipDir", Var, 0, ""},
@@ -9932,7 +9962,7 @@ var PackageSymbols = map[string][]Symbol{
{"PanicNilError", Type, 21, ""},
{"Pinner", Type, 21, ""},
{"ReadMemStats", Func, 0, "func(m *MemStats)"},
{"ReadTrace", Func, 5, "func() []byte"},
{"ReadTrace", Func, 5, "func() (buf []byte)"},
{"SetBlockProfileRate", Func, 1, "func(rate int)"},
{"SetCPUProfileRate", Func, 0, "func(hz int)"},
{"SetCgoTraceback", Func, 7, "func(version int, traceback unsafe.Pointer, context unsafe.Pointer, symbolizer unsafe.Pointer)"},
@@ -16679,6 +16709,7 @@ var PackageSymbols = map[string][]Symbol{
{"ValueOf", Func, 0, ""},
},
"testing": {
{"(*B).ArtifactDir", Method, 26, ""},
{"(*B).Attr", Method, 25, ""},
{"(*B).Chdir", Method, 24, ""},
{"(*B).Cleanup", Method, 14, ""},
@@ -16713,6 +16744,7 @@ var PackageSymbols = map[string][]Symbol{
{"(*B).StopTimer", Method, 0, ""},
{"(*B).TempDir", Method, 15, ""},
{"(*F).Add", Method, 18, ""},
{"(*F).ArtifactDir", Method, 26, ""},
{"(*F).Attr", Method, 25, ""},
{"(*F).Chdir", Method, 24, ""},
{"(*F).Cleanup", Method, 18, ""},
@@ -16738,6 +16770,7 @@ var PackageSymbols = map[string][]Symbol{
{"(*F).TempDir", Method, 18, ""},
{"(*M).Run", Method, 4, ""},
{"(*PB).Next", Method, 3, ""},
{"(*T).ArtifactDir", Method, 26, ""},
{"(*T).Attr", Method, 25, ""},
{"(*T).Chdir", Method, 24, ""},
{"(*T).Cleanup", Method, 14, ""},
+2 -4
View File
@@ -160,8 +160,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in
// 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)
for embedded := range u.EmbeddedTypes() {
if _, ok := embedded.Underlying().(*types.TypeParam); ok {
return nil, fmt.Errorf("invalid embedded type %T", embedded)
}
@@ -174,8 +173,7 @@ func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth in
case *types.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)
for t := range u.Terms() {
var terms termlist
switch t.Type().Underlying().(type) {
case *types.Interface:
+2 -2
View File
@@ -35,8 +35,8 @@ func ForEachElement(rtypes *typeutil.Map, msets *typeutil.MethodSetCache, T type
// Recursion over signatures of each method.
tmset := msets.MethodSet(T)
for i := 0; i < tmset.Len(); i++ {
sig := tmset.At(i).Type().(*types.Signature)
for method := range tmset.Methods() {
sig := method.Type().(*types.Signature)
// It is tempting to call visit(sig, false)
// but, as noted in golang.org/cl/65450043,
// the Signature.Recv field is ignored by
+49 -10
View File
@@ -19,25 +19,46 @@ func NoEffects(info *types.Info, expr ast.Expr) bool {
switch v := n.(type) {
case nil, *ast.Ident, *ast.BasicLit, *ast.BinaryExpr, *ast.ParenExpr,
*ast.SelectorExpr, *ast.IndexExpr, *ast.SliceExpr, *ast.TypeAssertExpr,
*ast.StarExpr, *ast.CompositeLit, *ast.ArrayType, *ast.StructType,
*ast.MapType, *ast.InterfaceType, *ast.KeyValueExpr:
// No effect
*ast.StarExpr, *ast.CompositeLit,
// non-expressions that may appear within expressions
*ast.KeyValueExpr,
*ast.FieldList,
*ast.Field,
*ast.Ellipsis,
*ast.IndexListExpr:
// No effect.
case *ast.ArrayType,
*ast.StructType,
*ast.ChanType,
*ast.FuncType,
*ast.MapType,
*ast.InterfaceType:
// Type syntax: no effects, recursively.
// Prune descent.
return false
case *ast.UnaryExpr:
// Channel send <-ch has effects
// Channel send <-ch has effects.
if v.Op == token.ARROW {
noEffects = false
}
case *ast.CallExpr:
// Type conversion has no effects
if !info.Types[v.Fun].IsType() {
// TODO(adonovan): Add a case for built-in functions without side
// effects (by using callsPureBuiltin from tools/internal/refactor/inline)
noEffects = false
case *ast.CallExpr:
// Type conversion has no effects.
if !info.Types[v.Fun].IsType() {
if CallsPureBuiltin(info, v) {
// A call such as len(e) has no effects of its
// own, though the subexpression e might.
} else {
noEffects = false
}
}
case *ast.FuncLit:
// A FuncLit has no effects, but do not descend into it.
return false
default:
// All other expressions have effects
noEffects = false
@@ -47,3 +68,21 @@ func NoEffects(info *types.Info, expr ast.Expr) bool {
})
return noEffects
}
// CallsPureBuiltin reports whether call is a call of a built-in
// function that is a pure computation over its operands (analogous to
// a + operator). Because it does not depend on program state, it may
// be evaluated at any point--though not necessarily at multiple
// points (consider new, make).
func CallsPureBuiltin(info *types.Info, call *ast.CallExpr) bool {
if id, ok := ast.Unparen(call.Fun).(*ast.Ident); ok {
if b, ok := info.ObjectOf(id).(*types.Builtin); ok {
switch b.Name() {
case "len", "cap", "complex", "imag", "real", "make", "new", "max", "min":
return true
}
// Not: append clear close copy delete panic print println recover
}
}
return false
}
+2 -2
View File
@@ -48,7 +48,7 @@ func IsFunctionNamed(obj types.Object, pkgPath string, names ...string) bool {
return ok &&
IsPackageLevel(obj) &&
f.Pkg().Path() == pkgPath &&
f.Type().(*types.Signature).Recv() == nil &&
f.Signature().Recv() == nil &&
slices.Contains(names, f.Name())
}
@@ -60,7 +60,7 @@ func IsFunctionNamed(obj types.Object, pkgPath string, names ...string) bool {
// which is important for the performance of syntax matching.
func IsMethodNamed(obj types.Object, pkgPath string, typeName string, names ...string) bool {
if fn, ok := obj.(*types.Func); ok {
if recv := fn.Type().(*types.Signature).Recv(); recv != nil {
if recv := fn.Signature().Recv(); recv != nil {
_, T := ReceiverNamed(recv)
return T != nil &&
IsTypeNamed(T, pkgPath, typeName) &&
+1 -1
View File
@@ -19,7 +19,7 @@ import (
// TODO(adonovan): this function ignores the effect of shadowing. It
// should accept a [token.Pos] and a [types.Info] and compute only the
// set of imports that are not shadowed at that point, analogous to
// [analysisinternal.AddImport]. It could also compute (as a side
// [analysis.AddImport]. It could also compute (as a side
// effect) the set of additional imports required to ensure that there
// is an accessible import for each necessary package, making it
// converge even more closely with AddImport.
+11 -28
View File
@@ -2,39 +2,22 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package typesinternal
//go:build go1.25
// TODO(adonovan): when CL 645115 lands, define the go1.25 version of
// this API that actually does something.
package typesinternal
import "go/types"
type VarKind uint8
type VarKind = types.VarKind
const (
_ VarKind = iota // (not meaningful)
PackageVar // a package-level variable
LocalVar // a local variable
RecvVar // a method receiver variable
ParamVar // a function parameter variable
ResultVar // a function result variable
FieldVar // a struct field
PackageVar = types.PackageVar
LocalVar = types.LocalVar
RecvVar = types.RecvVar
ParamVar = types.ParamVar
ResultVar = types.ResultVar
FieldVar = types.FieldVar
)
func (kind VarKind) String() string {
return [...]string{
0: "VarKind(0)",
PackageVar: "PackageVar",
LocalVar: "LocalVar",
RecvVar: "RecvVar",
ParamVar: "ParamVar",
ResultVar: "ResultVar",
FieldVar: "FieldVar",
}[kind]
}
// GetVarKind returns an invalid VarKind.
func GetVarKind(v *types.Var) VarKind { return 0 }
// SetVarKind has no effect.
func SetVarKind(v *types.Var, kind VarKind) {}
func GetVarKind(v *types.Var) VarKind { return v.Kind() }
func SetVarKind(v *types.Var, kind VarKind) { v.SetKind(kind) }
+39
View File
@@ -0,0 +1,39 @@
// 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.
//go:build !go1.25
package typesinternal
import "go/types"
type VarKind uint8
const (
_ VarKind = iota // (not meaningful)
PackageVar // a package-level variable
LocalVar // a local variable
RecvVar // a method receiver variable
ParamVar // a function parameter variable
ResultVar // a function result variable
FieldVar // a struct field
)
func (kind VarKind) String() string {
return [...]string{
0: "VarKind(0)",
PackageVar: "PackageVar",
LocalVar: "LocalVar",
RecvVar: "RecvVar",
ParamVar: "ParamVar",
ResultVar: "ResultVar",
FieldVar: "FieldVar",
}[kind]
}
// GetVarKind returns an invalid VarKind.
func GetVarKind(v *types.Var) VarKind { return 0 }
// SetVarKind has no effect.
func SetVarKind(v *types.Var, kind VarKind) {}
+7 -7
View File
@@ -258,12 +258,12 @@ func TypeExpr(t types.Type, qual types.Qualifier) ast.Expr {
case *types.Signature:
var params []*ast.Field
for i := 0; i < t.Params().Len(); i++ {
for v := range t.Params().Variables() {
params = append(params, &ast.Field{
Type: TypeExpr(t.Params().At(i).Type(), qual),
Type: TypeExpr(v.Type(), qual),
Names: []*ast.Ident{
{
Name: t.Params().At(i).Name(),
Name: v.Name(),
},
},
})
@@ -273,9 +273,9 @@ func TypeExpr(t types.Type, qual types.Qualifier) ast.Expr {
last.Type = &ast.Ellipsis{Elt: last.Type.(*ast.ArrayType).Elt}
}
var returns []*ast.Field
for i := 0; i < t.Results().Len(); i++ {
for v := range t.Results().Variables() {
returns = append(returns, &ast.Field{
Type: TypeExpr(t.Results().At(i).Type(), qual),
Type: TypeExpr(v.Type(), qual),
})
}
return &ast.FuncType{
@@ -315,8 +315,8 @@ func TypeExpr(t types.Type, qual types.Qualifier) ast.Expr {
if hasTypeArgs, ok := t.(interface{ TypeArgs() *types.TypeList }); ok {
if typeArgs := hasTypeArgs.TypeArgs(); typeArgs != nil && typeArgs.Len() > 0 {
var indices []ast.Expr
for i := range typeArgs.Len() {
indices = append(indices, TypeExpr(typeArgs.At(i), qual))
for t0 := range typeArgs.Types() {
indices = append(indices, TypeExpr(t0, qual))
}
expr = &ast.IndexListExpr{
X: expr,
+5 -1
View File
@@ -7,13 +7,17 @@ package versions
// This file contains predicates for working with file versions to
// decide when a tool should consider a language feature enabled.
// GoVersions that features in x/tools can be gated to.
// named constants, to avoid misspelling
const (
Go1_18 = "go1.18"
Go1_19 = "go1.19"
Go1_20 = "go1.20"
Go1_21 = "go1.21"
Go1_22 = "go1.22"
Go1_23 = "go1.23"
Go1_24 = "go1.24"
Go1_25 = "go1.25"
Go1_26 = "go1.26"
)
// Future is an invalid unknown Go version sometime in the future.
+9 -9
View File
@@ -41,7 +41,7 @@ github.com/jedisct1/dlog
# github.com/jedisct1/go-clocksmith v0.0.0-20250224222044-e151f21a353a
## explicit
github.com/jedisct1/go-clocksmith
# github.com/jedisct1/go-dnsstamps v0.0.0-20240423203910-07a0735c7774
# github.com/jedisct1/go-dnsstamps v0.0.0-20251112173516-191fc465df31
## explicit; go 1.18
github.com/jedisct1/go-dnsstamps
# github.com/jedisct1/go-hpke-compact v0.0.0-20241212093903-5caa4621366f
@@ -83,10 +83,10 @@ github.com/powerman/check
# github.com/powerman/deepequal v0.1.0
## explicit; go 1.16
github.com/powerman/deepequal
# github.com/quic-go/qpack v0.5.1
## explicit; go 1.22
# github.com/quic-go/qpack v0.6.0
## explicit; go 1.24
github.com/quic-go/qpack
# github.com/quic-go/quic-go v0.56.0
# github.com/quic-go/quic-go v0.57.1
## explicit; go 1.24
github.com/quic-go/quic-go
github.com/quic-go/quic-go/http3
@@ -110,7 +110,7 @@ github.com/quic-go/quic-go/quicvarint
## explicit; go 1.18
github.com/smartystreets/goconvey/convey/gotest
github.com/smartystreets/goconvey/convey/reporting
# golang.org/x/crypto v0.43.0
# golang.org/x/crypto v0.45.0
## explicit; go 1.24.0
golang.org/x/crypto/blake2b
golang.org/x/crypto/chacha20
@@ -124,10 +124,10 @@ golang.org/x/crypto/nacl/box
golang.org/x/crypto/nacl/secretbox
golang.org/x/crypto/poly1305
golang.org/x/crypto/salsa20/salsa
# golang.org/x/mod v0.29.0
# golang.org/x/mod v0.30.0
## explicit; go 1.24.0
golang.org/x/mod/semver
# golang.org/x/net v0.46.0
# golang.org/x/net v0.47.0
## explicit; go 1.24.0
golang.org/x/net/bpf
golang.org/x/net/http/httpguts
@@ -153,13 +153,13 @@ golang.org/x/sys/windows/registry
golang.org/x/sys/windows/svc
golang.org/x/sys/windows/svc/eventlog
golang.org/x/sys/windows/svc/mgr
# golang.org/x/text v0.30.0
# golang.org/x/text v0.31.0
## explicit; go 1.24.0
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.38.0
# golang.org/x/tools v0.39.0
## explicit; go 1.24.0
golang.org/x/tools/go/ast/edge
golang.org/x/tools/go/ast/inspector