mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-03-31 10:47:35 +03:00
Merge branch 'upstream' into sync-upstream
This commit is contained in:
commit
856bc02b8f
130 changed files with 1364 additions and 463 deletions
16
client.go
16
client.go
|
@ -57,11 +57,11 @@ func DialAddr(ctx context.Context, addr string, tlsConf *tls.Config, conf *Confi
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dl, err := setupTransport(udpConn, tlsConf, true)
|
||||
tr, err := setupTransport(udpConn, tlsConf, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dl.Dial(ctx, udpAddr, tlsConf, conf)
|
||||
return tr.dial(ctx, udpAddr, addr, tlsConf, conf, false)
|
||||
}
|
||||
|
||||
// DialAddrEarly establishes a new 0-RTT QUIC connection to a server.
|
||||
|
@ -75,13 +75,13 @@ func DialAddrEarly(ctx context.Context, addr string, tlsConf *tls.Config, conf *
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dl, err := setupTransport(udpConn, tlsConf, true)
|
||||
tr, err := setupTransport(udpConn, tlsConf, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := dl.DialEarly(ctx, udpAddr, tlsConf, conf)
|
||||
conn, err := tr.dial(ctx, udpAddr, addr, tlsConf, conf, true)
|
||||
if err != nil {
|
||||
dl.Close()
|
||||
tr.Close()
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
|
@ -166,12 +166,6 @@ func dial(
|
|||
}
|
||||
|
||||
func newClient(sendConn sendConn, connIDGenerator ConnectionIDGenerator, config *Config, tlsConf *tls.Config, onClose func(), use0RTT bool) (*client, error) {
|
||||
if tlsConf == nil {
|
||||
tlsConf = &tls.Config{}
|
||||
} else {
|
||||
tlsConf = tlsConf.Clone()
|
||||
}
|
||||
|
||||
srcConnID, err := connIDGenerator.GenerateConnectionID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -13,10 +13,9 @@ import (
|
|||
"github.com/refraction-networking/uquic/internal/utils"
|
||||
"github.com/refraction-networking/uquic/logging"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
type nullMultiplexer struct{}
|
||||
|
|
|
@ -244,7 +244,7 @@ var newConnection = func(
|
|||
handshakeDestConnID: destConnID,
|
||||
srcConnIDLen: srcConnID.Len(),
|
||||
tokenGenerator: tokenGenerator,
|
||||
oneRTTStream: newCryptoStream(),
|
||||
oneRTTStream: newCryptoStream(true),
|
||||
perspective: protocol.PerspectiveServer,
|
||||
tracer: tracer,
|
||||
logger: logger,
|
||||
|
@ -394,8 +394,7 @@ var newClientConnection = func(
|
|||
)
|
||||
|
||||
s.mtuDiscoverer = newMTUDiscoverer(s.rttStats, getMaxPacketSize(s.conn.RemoteAddr()), s.sentPacketHandler.SetMaxDatagramSize)
|
||||
oneRTTStream := newCryptoStream()
|
||||
|
||||
oneRTTStream := newCryptoStream(true)
|
||||
params := &wire.TransportParameters{
|
||||
InitialMaxStreamDataBidiRemote: protocol.ByteCount(s.config.InitialStreamReceiveWindow),
|
||||
InitialMaxStreamDataBidiLocal: protocol.ByteCount(s.config.InitialStreamReceiveWindow),
|
||||
|
@ -453,8 +452,8 @@ var newClientConnection = func(
|
|||
}
|
||||
|
||||
func (s *connection) preSetup() {
|
||||
s.initialStream = newCryptoStream()
|
||||
s.handshakeStream = newCryptoStream()
|
||||
s.initialStream = newCryptoStream(false)
|
||||
s.handshakeStream = newCryptoStream(false)
|
||||
s.sendQueue = newSendQueue(s.conn)
|
||||
s.retransmissionQueue = newRetransmissionQueue()
|
||||
s.frameParser = wire.NewFrameParser(s.config.EnableDatagrams)
|
||||
|
|
|
@ -26,10 +26,9 @@ import (
|
|||
"github.com/refraction-networking/uquic/internal/wire"
|
||||
"github.com/refraction-networking/uquic/logging"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func areConnsRunning() bool {
|
||||
|
@ -2703,8 +2702,9 @@ var _ = Describe("Client Connection", func() {
|
|||
Expect(recreateErr.nextPacketNumber).To(Equal(protocol.PacketNumber(128)))
|
||||
})
|
||||
|
||||
It("it closes when no matching version is found", func() {
|
||||
It("closes when no matching version is found", func() {
|
||||
errChan := make(chan error, 1)
|
||||
packer.EXPECT().PackCoalescedPacket(gomock.Any(), gomock.Any(), gomock.Any()).MaxTimes(1)
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
cryptoSetup.EXPECT().StartHandshake().MaxTimes(1)
|
||||
|
@ -2712,7 +2712,6 @@ var _ = Describe("Client Connection", func() {
|
|||
errChan <- conn.run()
|
||||
}()
|
||||
connRunner.EXPECT().Remove(srcConnID).MaxTimes(1)
|
||||
packer.EXPECT().PackCoalescedPacket(gomock.Any(), gomock.Any(), gomock.Any()).MaxTimes(1)
|
||||
gomock.InOrder(
|
||||
tracer.EXPECT().ReceivedVersionNegotiationPacket(gomock.Any(), gomock.Any(), gomock.Any()),
|
||||
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(e error) {
|
||||
|
|
|
@ -30,10 +30,17 @@ type cryptoStreamImpl struct {
|
|||
|
||||
writeOffset protocol.ByteCount
|
||||
writeBuf []byte
|
||||
|
||||
// Reassemble TLS handshake messages before returning them from GetCryptoData.
|
||||
// This is only needed because crypto/tls doesn't correctly handle post-handshake messages.
|
||||
onlyCompleteMsg bool
|
||||
}
|
||||
|
||||
func newCryptoStream() cryptoStream {
|
||||
return &cryptoStreamImpl{queue: newFrameSorter()}
|
||||
func newCryptoStream(onlyCompleteMsg bool) cryptoStream {
|
||||
return &cryptoStreamImpl{
|
||||
queue: newFrameSorter(),
|
||||
onlyCompleteMsg: onlyCompleteMsg,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *cryptoStreamImpl) HandleCryptoFrame(f *wire.CryptoFrame) error {
|
||||
|
@ -71,6 +78,20 @@ func (s *cryptoStreamImpl) HandleCryptoFrame(f *wire.CryptoFrame) error {
|
|||
|
||||
// GetCryptoData retrieves data that was received in CRYPTO frames
|
||||
func (s *cryptoStreamImpl) GetCryptoData() []byte {
|
||||
if s.onlyCompleteMsg {
|
||||
if len(s.msgBuf) < 4 {
|
||||
return nil
|
||||
}
|
||||
msgLen := 4 + int(s.msgBuf[1])<<16 + int(s.msgBuf[2])<<8 + int(s.msgBuf[3])
|
||||
if len(s.msgBuf) < msgLen {
|
||||
return nil
|
||||
}
|
||||
msg := make([]byte, msgLen)
|
||||
copy(msg, s.msgBuf[:msgLen])
|
||||
s.msgBuf = s.msgBuf[msgLen:]
|
||||
return msg
|
||||
}
|
||||
|
||||
b := s.msgBuf
|
||||
s.msgBuf = nil
|
||||
return b
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package quic
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
|
||||
"github.com/refraction-networking/uquic/internal/protocol"
|
||||
|
@ -15,7 +16,7 @@ var _ = Describe("Crypto Stream", func() {
|
|||
var str cryptoStream
|
||||
|
||||
BeforeEach(func() {
|
||||
str = newCryptoStream()
|
||||
str = newCryptoStream(false)
|
||||
})
|
||||
|
||||
Context("handling incoming data", func() {
|
||||
|
@ -137,4 +138,23 @@ var _ = Describe("Crypto Stream", func() {
|
|||
Expect(f.Data).To(Equal([]byte("bar")))
|
||||
})
|
||||
})
|
||||
|
||||
It("reassembles data", func() {
|
||||
str = newCryptoStream(true)
|
||||
data := make([]byte, 1337)
|
||||
l := len(data) - 4
|
||||
data[1] = uint8(l >> 16)
|
||||
data[2] = uint8(l >> 8)
|
||||
data[3] = uint8(l)
|
||||
rand.Read(data[4:])
|
||||
|
||||
for i, b := range data {
|
||||
Expect(str.GetCryptoData()).To(BeEmpty())
|
||||
Expect(str.HandleCryptoFrame(&wire.CryptoFrame{
|
||||
Offset: protocol.ByteCount(i),
|
||||
Data: []byte{b},
|
||||
})).To(Succeed())
|
||||
}
|
||||
Expect(str.GetCryptoData()).To(Equal(data))
|
||||
})
|
||||
})
|
||||
|
|
|
@ -8,10 +8,9 @@ import (
|
|||
"github.com/refraction-networking/uquic/internal/protocol"
|
||||
"github.com/refraction-networking/uquic/internal/wire"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
var _ = Describe("Framer", func() {
|
||||
|
|
|
@ -85,33 +85,6 @@ func (m messageType) String() string {
|
|||
}
|
||||
}
|
||||
|
||||
func appendSuites(suites []uint16, rand uint8) []uint16 {
|
||||
const (
|
||||
s1 = tls.TLS_AES_128_GCM_SHA256
|
||||
s2 = tls.TLS_AES_256_GCM_SHA384
|
||||
s3 = tls.TLS_CHACHA20_POLY1305_SHA256
|
||||
)
|
||||
switch rand % 4 {
|
||||
default:
|
||||
return suites
|
||||
case 1:
|
||||
return append(suites, s1)
|
||||
case 2:
|
||||
return append(suites, s2)
|
||||
case 3:
|
||||
return append(suites, s3)
|
||||
}
|
||||
}
|
||||
|
||||
// consumes 2 bits
|
||||
func getSuites(rand uint8) []uint16 {
|
||||
suites := make([]uint16, 0, 3)
|
||||
for i := 1; i <= 3; i++ {
|
||||
suites = appendSuites(suites, rand>>i%4)
|
||||
}
|
||||
return suites
|
||||
}
|
||||
|
||||
// consumes 3 bits
|
||||
func getClientAuth(rand uint8) tls.ClientAuthType {
|
||||
switch rand {
|
||||
|
@ -148,6 +121,7 @@ func getTransportParameters(seed uint8) *wire.TransportParameters {
|
|||
const maxVarInt = math.MaxUint64 / 4
|
||||
r := mrand.New(mrand.NewSource(int64(seed)))
|
||||
return &wire.TransportParameters{
|
||||
ActiveConnectionIDLimit: 2,
|
||||
InitialMaxData: protocol.ByteCount(r.Int63n(maxVarInt)),
|
||||
InitialMaxStreamDataBidiLocal: protocol.ByteCount(r.Int63n(maxVarInt)),
|
||||
InitialMaxStreamDataBidiRemote: protocol.ByteCount(r.Int63n(maxVarInt)),
|
||||
|
@ -207,14 +181,26 @@ func runHandshake(runConfig [confLen]byte, messageConfig uint8, clientConf *tls.
|
|||
SessionTicketKey: sessionTicketKey,
|
||||
}
|
||||
|
||||
// This sets the cipher suite for both client and server.
|
||||
// The way crypto/tls is designed doesn't allow us to set different cipher suites for client and server.
|
||||
resetCipherSuite := func() {}
|
||||
switch (runConfig[0] >> 6) % 4 {
|
||||
case 0:
|
||||
resetCipherSuite = qtls.SetCipherSuite(tls.TLS_AES_128_GCM_SHA256)
|
||||
case 1:
|
||||
resetCipherSuite = qtls.SetCipherSuite(tls.TLS_AES_256_GCM_SHA384)
|
||||
case 3:
|
||||
resetCipherSuite = qtls.SetCipherSuite(tls.TLS_CHACHA20_POLY1305_SHA256)
|
||||
default:
|
||||
}
|
||||
defer resetCipherSuite()
|
||||
|
||||
enable0RTTClient := helper.NthBit(runConfig[0], 0)
|
||||
enable0RTTServer := helper.NthBit(runConfig[0], 1)
|
||||
sendPostHandshakeMessageToClient := helper.NthBit(runConfig[0], 3)
|
||||
sendPostHandshakeMessageToServer := helper.NthBit(runConfig[0], 4)
|
||||
sendSessionTicket := helper.NthBit(runConfig[0], 5)
|
||||
clientConf.CipherSuites = getSuites(runConfig[0] >> 6)
|
||||
serverConf.ClientAuth = getClientAuth(runConfig[1] & 0b00000111)
|
||||
serverConf.CipherSuites = getSuites(runConfig[1] >> 6)
|
||||
serverConf.SessionTicketsDisabled = helper.NthBit(runConfig[1], 3)
|
||||
if helper.NthBit(runConfig[2], 0) {
|
||||
clientConf.RootCAs = x509.NewCertPool()
|
||||
|
@ -303,6 +289,7 @@ func runHandshake(runConfig [confLen]byte, messageConfig uint8, clientConf *tls.
|
|||
if err := client.StartHandshake(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
server := handshake.NewCryptoSetupServer(
|
||||
protocol.ConnectionID{},
|
||||
|
@ -319,12 +306,13 @@ func runHandshake(runConfig [confLen]byte, messageConfig uint8, clientConf *tls.
|
|||
if err := server.StartHandshake(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer server.Close()
|
||||
|
||||
var clientHandshakeComplete, serverHandshakeComplete bool
|
||||
for {
|
||||
var processedEvent bool
|
||||
clientLoop:
|
||||
for {
|
||||
var processedEvent bool
|
||||
ev := client.NextEvent()
|
||||
//nolint:exhaustive // only need to process a few events
|
||||
switch ev.Kind {
|
||||
|
@ -335,11 +323,16 @@ func runHandshake(runConfig [confLen]byte, messageConfig uint8, clientConf *tls.
|
|||
break clientLoop
|
||||
case handshake.EventWriteInitialData, handshake.EventWriteHandshakeData:
|
||||
msg := ev.Data
|
||||
encLevel := protocol.EncryptionInitial
|
||||
if ev.Kind == handshake.EventWriteHandshakeData {
|
||||
encLevel = protocol.EncryptionHandshake
|
||||
}
|
||||
if msg[0] == messageToReplace {
|
||||
fmt.Printf("replacing %s message to the server with %s at %s\n", messageType(msg[0]), messageType(data[0]), messageToReplaceEncLevel)
|
||||
msg = data
|
||||
encLevel = messageToReplaceEncLevel
|
||||
}
|
||||
if err := server.HandleMessage(msg, messageToReplaceEncLevel); err != nil {
|
||||
if err := server.HandleMessage(msg, encLevel); err != nil {
|
||||
return 1
|
||||
}
|
||||
case handshake.EventHandshakeComplete:
|
||||
|
@ -348,9 +341,9 @@ func runHandshake(runConfig [confLen]byte, messageConfig uint8, clientConf *tls.
|
|||
processedEvent = true
|
||||
}
|
||||
|
||||
processedEvent = false
|
||||
serverLoop:
|
||||
for {
|
||||
var processedEvent bool
|
||||
ev := server.NextEvent()
|
||||
//nolint:exhaustive // only need to process a few events
|
||||
switch ev.Kind {
|
||||
|
@ -360,12 +353,17 @@ func runHandshake(runConfig [confLen]byte, messageConfig uint8, clientConf *tls.
|
|||
}
|
||||
break serverLoop
|
||||
case handshake.EventWriteInitialData, handshake.EventWriteHandshakeData:
|
||||
encLevel := protocol.EncryptionInitial
|
||||
if ev.Kind == handshake.EventWriteHandshakeData {
|
||||
encLevel = protocol.EncryptionHandshake
|
||||
}
|
||||
msg := ev.Data
|
||||
if msg[0] == messageToReplace {
|
||||
fmt.Printf("replacing %s message to the client with %s at %s\n", messageType(msg[0]), messageType(data[0]), messageToReplaceEncLevel)
|
||||
msg = data
|
||||
encLevel = messageToReplaceEncLevel
|
||||
}
|
||||
if err := client.HandleMessage(msg, messageToReplaceEncLevel); err != nil {
|
||||
if err := client.HandleMessage(msg, encLevel); err != nil {
|
||||
return 1
|
||||
}
|
||||
case handshake.EventHandshakeComplete:
|
||||
|
@ -410,10 +408,13 @@ func runHandshake(runConfig [confLen]byte, messageConfig uint8, clientConf *tls.
|
|||
}
|
||||
client.HandleMessage(ticket, protocol.Encryption1RTT)
|
||||
}
|
||||
|
||||
if sendPostHandshakeMessageToClient {
|
||||
fmt.Println("sending post handshake message to the client at", messageToReplaceEncLevel)
|
||||
client.HandleMessage(data, messageToReplaceEncLevel)
|
||||
}
|
||||
if sendPostHandshakeMessageToServer {
|
||||
fmt.Println("sending post handshake message to the server at", messageToReplaceEncLevel)
|
||||
server.HandleMessage(data, messageToReplaceEncLevel)
|
||||
}
|
||||
|
||||
|
|
6
go.sum
6
go.sum
|
@ -40,8 +40,6 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
|
|||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
|
@ -133,8 +131,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
||||
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
go.uber.org/mock v0.2.0 h1:TaP3xedm7JaAgScZO7tlvlKrqT0p7I6OsdGB5YNSMDU=
|
||||
go.uber.org/mock v0.2.0/go.mod h1:J0y0rp9L3xiff1+ZBfKxlC1fz2+aO16tw0tsDOixfuM=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
|
@ -200,7 +199,6 @@ golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
|||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
|
|
|
@ -6,9 +6,9 @@ import (
|
|||
quic "github.com/refraction-networking/uquic"
|
||||
mockquic "github.com/refraction-networking/uquic/internal/mocks/quic"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
var _ = Describe("Response Body", func() {
|
||||
|
|
|
@ -19,11 +19,11 @@ import (
|
|||
"github.com/refraction-networking/uquic/internal/utils"
|
||||
"github.com/refraction-networking/uquic/quicvarint"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/quic-go/qpack"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
var _ = Describe("Client", func() {
|
||||
|
|
|
@ -26,7 +26,7 @@ const (
|
|||
ErrCodeMessageError ErrCode = 0x10e
|
||||
ErrCodeConnectError ErrCode = 0x10f
|
||||
ErrCodeVersionFallback ErrCode = 0x110
|
||||
ErrCodeDatagramError ErrCode = 0x4a1268
|
||||
ErrCodeDatagramError ErrCode = 0x33
|
||||
)
|
||||
|
||||
func (e ErrCode) String() string {
|
||||
|
|
|
@ -88,7 +88,7 @@ func (f *headersFrame) Append(b []byte) []byte {
|
|||
return quicvarint.Append(b, f.Length)
|
||||
}
|
||||
|
||||
const settingDatagram = 0xffd277
|
||||
const settingDatagram = 0x33
|
||||
|
||||
type settingsFrame struct {
|
||||
Datagram bool
|
||||
|
|
|
@ -6,10 +6,9 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestHttp3(t *testing.T) {
|
||||
|
|
|
@ -7,9 +7,9 @@ import (
|
|||
quic "github.com/refraction-networking/uquic"
|
||||
mockquic "github.com/refraction-networking/uquic/internal/mocks/quic"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func getDataFrame(data []byte) []byte {
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
net "net"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
quic "github.com/refraction-networking/uquic"
|
||||
)
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
http "net/http"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockRoundTripCloser is a mock of RoundTripCloser interface.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
package http3
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package http3 -destination mock_roundtripcloser_test.go github.com/refraction-networking/uquic/http3 RoundTripCloser"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package http3 -destination mock_roundtripcloser_test.go github.com/refraction-networking/uquic/http3 RoundTripCloser"
|
||||
type RoundTripCloser = roundTripCloser
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package http3 -destination mock_quic_early_listener_test.go github.com/refraction-networking/uquic/http3 QUICEarlyListener"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -package http3 -destination mock_quic_early_listener_test.go github.com/refraction-networking/uquic/http3 QUICEarlyListener"
|
||||
|
|
|
@ -8,8 +8,8 @@ import (
|
|||
mockquic "github.com/refraction-networking/uquic/internal/mocks/quic"
|
||||
"github.com/refraction-networking/uquic/internal/utils"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/quic-go/qpack"
|
||||
"go.uber.org/mock/gomock"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
|
|
|
@ -15,19 +15,61 @@ import (
|
|||
"github.com/quic-go/qpack"
|
||||
)
|
||||
|
||||
// The maximum length of an encoded HTTP/3 frame header is 16:
|
||||
// The frame has a type and length field, both QUIC varints (maximum 8 bytes in length)
|
||||
const frameHeaderLen = 16
|
||||
|
||||
// headerWriter wraps the stream, so that the first Write call flushes the header to the stream
|
||||
type headerWriter struct {
|
||||
str quic.Stream
|
||||
header http.Header
|
||||
status int // status code passed to WriteHeader
|
||||
written bool
|
||||
|
||||
logger utils.Logger
|
||||
}
|
||||
|
||||
// writeHeader encodes and flush header to the stream
|
||||
func (hw *headerWriter) writeHeader() error {
|
||||
var headers bytes.Buffer
|
||||
enc := qpack.NewEncoder(&headers)
|
||||
enc.WriteField(qpack.HeaderField{Name: ":status", Value: strconv.Itoa(hw.status)})
|
||||
|
||||
for k, v := range hw.header {
|
||||
for index := range v {
|
||||
enc.WriteField(qpack.HeaderField{Name: strings.ToLower(k), Value: v[index]})
|
||||
}
|
||||
}
|
||||
|
||||
buf := make([]byte, 0, frameHeaderLen+headers.Len())
|
||||
buf = (&headersFrame{Length: uint64(headers.Len())}).Append(buf)
|
||||
hw.logger.Infof("Responding with %d", hw.status)
|
||||
buf = append(buf, headers.Bytes()...)
|
||||
|
||||
_, err := hw.str.Write(buf)
|
||||
return err
|
||||
}
|
||||
|
||||
// first Write will trigger flushing header
|
||||
func (hw *headerWriter) Write(p []byte) (int, error) {
|
||||
if !hw.written {
|
||||
if err := hw.writeHeader(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
hw.written = true
|
||||
}
|
||||
return hw.str.Write(p)
|
||||
}
|
||||
|
||||
type responseWriter struct {
|
||||
*headerWriter
|
||||
conn quic.Connection
|
||||
str quic.Stream
|
||||
bufferedStr *bufio.Writer
|
||||
buf []byte
|
||||
|
||||
header http.Header
|
||||
status int // status code passed to WriteHeader
|
||||
headerWritten bool
|
||||
contentLen int64 // if handler set valid Content-Length header
|
||||
numWritten int64 // bytes written
|
||||
|
||||
logger utils.Logger
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -37,13 +79,16 @@ var (
|
|||
)
|
||||
|
||||
func newResponseWriter(str quic.Stream, conn quic.Connection, logger utils.Logger) *responseWriter {
|
||||
hw := &headerWriter{
|
||||
str: str,
|
||||
header: http.Header{},
|
||||
logger: logger,
|
||||
}
|
||||
return &responseWriter{
|
||||
header: http.Header{},
|
||||
buf: make([]byte, 16),
|
||||
conn: conn,
|
||||
str: str,
|
||||
bufferedStr: bufio.NewWriter(str),
|
||||
logger: logger,
|
||||
headerWriter: hw,
|
||||
buf: make([]byte, frameHeaderLen),
|
||||
conn: conn,
|
||||
bufferedStr: bufio.NewWriter(hw),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,27 +128,8 @@ func (w *responseWriter) WriteHeader(status int) {
|
|||
}
|
||||
w.status = status
|
||||
|
||||
var headers bytes.Buffer
|
||||
enc := qpack.NewEncoder(&headers)
|
||||
enc.WriteField(qpack.HeaderField{Name: ":status", Value: strconv.Itoa(status)})
|
||||
|
||||
for k, v := range w.header {
|
||||
for index := range v {
|
||||
enc.WriteField(qpack.HeaderField{Name: strings.ToLower(k), Value: v[index]})
|
||||
}
|
||||
}
|
||||
|
||||
w.buf = w.buf[:0]
|
||||
w.buf = (&headersFrame{Length: uint64(headers.Len())}).Append(w.buf)
|
||||
w.logger.Infof("Responding with %d", status)
|
||||
if _, err := w.bufferedStr.Write(w.buf); err != nil {
|
||||
w.logger.Errorf("could not write headers frame: %s", err.Error())
|
||||
}
|
||||
if _, err := w.bufferedStr.Write(headers.Bytes()); err != nil {
|
||||
w.logger.Errorf("could not write header frame payload: %s", err.Error())
|
||||
}
|
||||
if !w.headerWritten {
|
||||
w.Flush()
|
||||
w.writeHeader()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,6 +172,15 @@ func (w *responseWriter) Write(p []byte) (int, error) {
|
|||
}
|
||||
|
||||
func (w *responseWriter) FlushError() error {
|
||||
if !w.headerWritten {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
if !w.written {
|
||||
if err := w.writeHeader(); err != nil {
|
||||
return err
|
||||
}
|
||||
w.written = true
|
||||
}
|
||||
return w.bufferedStr.Flush()
|
||||
}
|
||||
|
||||
|
|
|
@ -9,11 +9,11 @@ import (
|
|||
mockquic "github.com/refraction-networking/uquic/internal/mocks/quic"
|
||||
"github.com/refraction-networking/uquic/internal/utils"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/quic-go/qpack"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
var _ = Describe("Response Writer", func() {
|
||||
|
|
|
@ -52,7 +52,7 @@ type RoundTripper struct {
|
|||
|
||||
// Enable support for HTTP/3 datagrams.
|
||||
// If set to true, QuicConfig.EnableDatagram will be set.
|
||||
// See https://www.ietf.org/archive/id/draft-schinazi-masque-h3-datagram-02.html.
|
||||
// See https://datatracker.ietf.org/doc/html/rfc9297.
|
||||
EnableDatagrams bool
|
||||
|
||||
// Additional HTTP/3 settings.
|
||||
|
|
|
@ -14,9 +14,9 @@ import (
|
|||
|
||||
"github.com/refraction-networking/uquic/internal/qerr"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
type mockBody struct {
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -33,12 +34,8 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
const (
|
||||
// NextProtoH3Draft29 is the ALPN protocol negotiated during the TLS handshake, for QUIC draft 29.
|
||||
NextProtoH3Draft29 = "h3-29"
|
||||
// NextProtoH3 is the ALPN protocol negotiated during the TLS handshake, for QUIC v1 and v2.
|
||||
NextProtoH3 = "h3"
|
||||
)
|
||||
// NextProtoH3 is the ALPN protocol negotiated during the TLS handshake, for QUIC v1 and v2.
|
||||
const NextProtoH3 = "h3"
|
||||
|
||||
// StreamType is the stream type of a unidirectional stream.
|
||||
type StreamType uint64
|
||||
|
@ -178,7 +175,7 @@ type Server struct {
|
|||
|
||||
// EnableDatagrams enables support for HTTP/3 datagrams.
|
||||
// If set to true, QuicConfig.EnableDatagram will be set.
|
||||
// See https://datatracker.ietf.org/doc/html/draft-ietf-masque-h3-datagram-07.
|
||||
// See https://datatracker.ietf.org/doc/html/rfc9297.
|
||||
EnableDatagrams bool
|
||||
|
||||
// MaxHeaderBytes controls the maximum number of bytes the server will
|
||||
|
@ -651,7 +648,12 @@ func (s *Server) handleRequest(conn quic.Connection, str quic.Stream, decoder *q
|
|||
|
||||
// only write response when there is no panic
|
||||
if !panicked {
|
||||
r.WriteHeader(http.StatusOK)
|
||||
// response not written to the client yet, set Content-Length
|
||||
if !r.written {
|
||||
if _, haveCL := r.header["Content-Length"]; !haveCL {
|
||||
r.header.Set("Content-Length", strconv.FormatInt(r.numWritten, 10))
|
||||
}
|
||||
}
|
||||
r.Flush()
|
||||
}
|
||||
// If the EOF was read by the handler, CancelRead() is a no-op.
|
||||
|
|
|
@ -21,8 +21,8 @@ import (
|
|||
"github.com/refraction-networking/uquic/internal/utils"
|
||||
"github.com/refraction-networking/uquic/quicvarint"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/quic-go/qpack"
|
||||
"go.uber.org/mock/gomock"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
|
@ -181,6 +181,47 @@ var _ = Describe("Server", func() {
|
|||
Expect(hfs).To(HaveKeyWithValue(":status", []string{"200"}))
|
||||
})
|
||||
|
||||
It("sets Content-Length when the handler doesn't flush to the client", func() {
|
||||
s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("foobar"))
|
||||
})
|
||||
|
||||
responseBuf := &bytes.Buffer{}
|
||||
setRequest(encodeRequest(exampleGetRequest))
|
||||
str.EXPECT().Context().Return(reqContext)
|
||||
str.EXPECT().Write(gomock.Any()).DoAndReturn(responseBuf.Write).AnyTimes()
|
||||
str.EXPECT().CancelRead(gomock.Any())
|
||||
|
||||
serr := s.handleRequest(conn, str, qpackDecoder, nil)
|
||||
Expect(serr.err).ToNot(HaveOccurred())
|
||||
hfs := decodeHeader(responseBuf)
|
||||
Expect(hfs).To(HaveKeyWithValue(":status", []string{"200"}))
|
||||
Expect(hfs).To(HaveKeyWithValue("content-length", []string{"6"}))
|
||||
// status, content-length, date, content-type
|
||||
Expect(hfs).To(HaveLen(4))
|
||||
})
|
||||
|
||||
It("not sets Content-Length when the handler flushes to the client", func() {
|
||||
s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("foobar"))
|
||||
// force flush
|
||||
w.(http.Flusher).Flush()
|
||||
})
|
||||
|
||||
responseBuf := &bytes.Buffer{}
|
||||
setRequest(encodeRequest(exampleGetRequest))
|
||||
str.EXPECT().Context().Return(reqContext)
|
||||
str.EXPECT().Write(gomock.Any()).DoAndReturn(responseBuf.Write).AnyTimes()
|
||||
str.EXPECT().CancelRead(gomock.Any())
|
||||
|
||||
serr := s.handleRequest(conn, str, qpackDecoder, nil)
|
||||
Expect(serr.err).ToNot(HaveOccurred())
|
||||
hfs := decodeHeader(responseBuf)
|
||||
Expect(hfs).To(HaveKeyWithValue(":status", []string{"200"}))
|
||||
// status, date, content-type
|
||||
Expect(hfs).To(HaveLen(3))
|
||||
})
|
||||
|
||||
It("handles a aborting handler", func() {
|
||||
s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
panic(http.ErrAbortHandler)
|
||||
|
|
|
@ -39,8 +39,6 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
|
|||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
|
@ -136,8 +134,8 @@ github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7q
|
|||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.0 h1:NrCXmDl8BddZwO67vlvEpBTwT89bJfKYygxv4HQvuDk=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.0/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
|
||||
|
@ -173,10 +171,11 @@ github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cb
|
|||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
||||
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
go.uber.org/mock v0.2.0 h1:TaP3xedm7JaAgScZO7tlvlKrqT0p7I6OsdGB5YNSMDU=
|
||||
go.uber.org/mock v0.2.0/go.mod h1:J0y0rp9L3xiff1+ZBfKxlC1fz2+aO16tw0tsDOixfuM=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
|
@ -195,7 +194,7 @@ golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTk
|
|||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
||||
|
@ -217,7 +216,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
|
@ -261,9 +259,7 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
@ -309,7 +305,7 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
|
|||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||
|
|
|
@ -201,6 +201,8 @@ var _ = Describe("Handshake tests", func() {
|
|||
Expect(errors.As(err, &transportErr)).To(BeTrue())
|
||||
Expect(transportErr.ErrorCode.IsCryptoError()).To(BeTrue())
|
||||
Expect(transportErr.Error()).To(ContainSubstring("x509: certificate is valid for localhost, not foo.bar"))
|
||||
var certErr *tls.CertificateVerificationError
|
||||
Expect(errors.As(transportErr, &certErr)).To(BeTrue())
|
||||
})
|
||||
|
||||
It("fails the handshake if the client fails to provide the requested client cert", func() {
|
||||
|
@ -452,7 +454,7 @@ var _ = Describe("Handshake tests", func() {
|
|||
|
||||
It("rejects invalid Retry token with the INVALID_TOKEN error", func() {
|
||||
serverConfig.RequireAddressValidation = func(net.Addr) bool { return true }
|
||||
serverConfig.MaxRetryTokenAge = time.Nanosecond
|
||||
serverConfig.MaxRetryTokenAge = -time.Second
|
||||
|
||||
server, err := quic.ListenAddr("localhost:0", getTLSConfig(), serverConfig)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
|
|
@ -42,7 +42,7 @@ var _ = Describe("HTTP tests", func() {
|
|||
rt *http3.RoundTripper
|
||||
server *http3.Server
|
||||
stoppedServing chan struct{}
|
||||
port string
|
||||
port int
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
|
@ -93,7 +93,7 @@ var _ = Describe("HTTP tests", func() {
|
|||
Expect(err).NotTo(HaveOccurred())
|
||||
conn, err := net.ListenUDP("udp", addr)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
port = strconv.Itoa(conn.LocalAddr().(*net.UDPAddr).Port)
|
||||
port = conn.LocalAddr().(*net.UDPAddr).Port
|
||||
|
||||
stoppedServing = make(chan struct{})
|
||||
|
||||
|
@ -120,7 +120,7 @@ var _ = Describe("HTTP tests", func() {
|
|||
})
|
||||
|
||||
It("downloads a hello", func() {
|
||||
resp, err := client.Get("https://localhost:" + port + "/hello")
|
||||
resp, err := client.Get(fmt.Sprintf("https://localhost:%d/hello", port))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resp.StatusCode).To(Equal(200))
|
||||
body, err := io.ReadAll(gbytes.TimeoutReader(resp.Body, 3*time.Second))
|
||||
|
@ -128,13 +128,25 @@ var _ = Describe("HTTP tests", func() {
|
|||
Expect(string(body)).To(Equal("Hello, World!\n"))
|
||||
})
|
||||
|
||||
It("sets content-length for small response", func() {
|
||||
mux.HandleFunc("/small", func(w http.ResponseWriter, r *http.Request) {
|
||||
defer GinkgoRecover()
|
||||
w.Write([]byte("foobar"))
|
||||
})
|
||||
|
||||
resp, err := client.Get(fmt.Sprintf("https://localhost:%d/small", port))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resp.StatusCode).To(Equal(200))
|
||||
Expect(resp.Header.Get("Content-Length")).To(Equal(strconv.Itoa(len("foobar"))))
|
||||
})
|
||||
|
||||
It("requests to different servers with the same udpconn", func() {
|
||||
resp, err := client.Get("https://localhost:" + port + "/remoteAddr")
|
||||
resp, err := client.Get(fmt.Sprintf("https://localhost:%d/remoteAddr", port))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resp.StatusCode).To(Equal(200))
|
||||
addr1 := resp.Header.Get("X-RemoteAddr")
|
||||
Expect(addr1).ToNot(Equal(""))
|
||||
resp, err = client.Get("https://127.0.0.1:" + port + "/remoteAddr")
|
||||
resp, err = client.Get(fmt.Sprintf("https://127.0.0.1:%d/remoteAddr", port))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resp.StatusCode).To(Equal(200))
|
||||
addr2 := resp.Header.Get("X-RemoteAddr")
|
||||
|
@ -146,7 +158,7 @@ var _ = Describe("HTTP tests", func() {
|
|||
group, ctx := errgroup.WithContext(context.Background())
|
||||
for i := 0; i < 2; i++ {
|
||||
group.Go(func() error {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://localhost:"+port+"/hello", nil)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("https://localhost:%d/hello", port), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
resp, err := client.Do(req)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
@ -172,7 +184,7 @@ var _ = Describe("HTTP tests", func() {
|
|||
close(handlerCalled)
|
||||
})
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "https://localhost:"+port+"/headers/request", nil)
|
||||
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("https://localhost:%d/headers/request", port), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
req.Header.Set("foo", "bar")
|
||||
req.Header.Set("lorem", "ipsum")
|
||||
|
@ -189,7 +201,7 @@ var _ = Describe("HTTP tests", func() {
|
|||
w.Header().Set("lorem", "ipsum")
|
||||
})
|
||||
|
||||
resp, err := client.Get("https://localhost:" + port + "/headers/response")
|
||||
resp, err := client.Get(fmt.Sprintf("https://localhost:%d/headers/response", port))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resp.StatusCode).To(Equal(200))
|
||||
Expect(resp.Header.Get("foo")).To(Equal("bar"))
|
||||
|
@ -197,7 +209,7 @@ var _ = Describe("HTTP tests", func() {
|
|||
})
|
||||
|
||||
It("downloads a small file", func() {
|
||||
resp, err := client.Get("https://localhost:" + port + "/prdata")
|
||||
resp, err := client.Get(fmt.Sprintf("https://localhost:%d/prdata", port))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resp.StatusCode).To(Equal(200))
|
||||
body, err := io.ReadAll(gbytes.TimeoutReader(resp.Body, 5*time.Second))
|
||||
|
@ -206,7 +218,7 @@ var _ = Describe("HTTP tests", func() {
|
|||
})
|
||||
|
||||
It("downloads a large file", func() {
|
||||
resp, err := client.Get("https://localhost:" + port + "/prdatalong")
|
||||
resp, err := client.Get(fmt.Sprintf("https://localhost:%d/prdatalong", port))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resp.StatusCode).To(Equal(200))
|
||||
body, err := io.ReadAll(gbytes.TimeoutReader(resp.Body, 20*time.Second))
|
||||
|
@ -218,7 +230,7 @@ var _ = Describe("HTTP tests", func() {
|
|||
const num = 150
|
||||
|
||||
for i := 0; i < num; i++ {
|
||||
resp, err := client.Get("https://localhost:" + port + "/hello")
|
||||
resp, err := client.Get(fmt.Sprintf("https://localhost:%d/hello", port))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resp.StatusCode).To(Equal(200))
|
||||
body, err := io.ReadAll(gbytes.TimeoutReader(resp.Body, 3*time.Second))
|
||||
|
@ -231,7 +243,7 @@ var _ = Describe("HTTP tests", func() {
|
|||
const num = 150
|
||||
|
||||
for i := 0; i < num; i++ {
|
||||
resp, err := client.Get("https://localhost:" + port + "/prdata")
|
||||
resp, err := client.Get(fmt.Sprintf("https://localhost:%d/prdata", port))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resp.StatusCode).To(Equal(200))
|
||||
Expect(resp.Body.Close()).To(Succeed())
|
||||
|
@ -240,7 +252,7 @@ var _ = Describe("HTTP tests", func() {
|
|||
|
||||
It("posts a small message", func() {
|
||||
resp, err := client.Post(
|
||||
"https://localhost:"+port+"/echo",
|
||||
fmt.Sprintf("https://localhost:%d/echo", port),
|
||||
"text/plain",
|
||||
bytes.NewReader([]byte("Hello, world!")),
|
||||
)
|
||||
|
@ -253,7 +265,7 @@ var _ = Describe("HTTP tests", func() {
|
|||
|
||||
It("uploads a file", func() {
|
||||
resp, err := client.Post(
|
||||
"https://localhost:"+port+"/echo",
|
||||
fmt.Sprintf("https://localhost:%d/echo", port),
|
||||
"text/plain",
|
||||
bytes.NewReader(PRData),
|
||||
)
|
||||
|
@ -277,7 +289,7 @@ var _ = Describe("HTTP tests", func() {
|
|||
})
|
||||
|
||||
client.Transport.(*http3.RoundTripper).DisableCompression = false
|
||||
resp, err := client.Get("https://localhost:" + port + "/gzipped/hello")
|
||||
resp, err := client.Get(fmt.Sprintf("https://localhost:%d/gzipped/hello", port))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resp.StatusCode).To(Equal(200))
|
||||
Expect(resp.Uncompressed).To(BeTrue())
|
||||
|
@ -303,7 +315,7 @@ var _ = Describe("HTTP tests", func() {
|
|||
}
|
||||
})
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "https://localhost:"+port+"/cancel", nil)
|
||||
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("https://localhost:%d/cancel", port), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
req = req.WithContext(ctx)
|
||||
|
@ -336,7 +348,7 @@ var _ = Describe("HTTP tests", func() {
|
|||
})
|
||||
|
||||
r, w := io.Pipe()
|
||||
req, err := http.NewRequest("PUT", "https://localhost:"+port+"/echoline", r)
|
||||
req, err := http.NewRequest(http.MethodPut, fmt.Sprintf("https://localhost:%d/echoline", port), r)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
rsp, err := client.Do(req)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
@ -373,7 +385,7 @@ var _ = Describe("HTTP tests", func() {
|
|||
}()
|
||||
})
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "https://localhost:"+port+"/httpstreamer", nil)
|
||||
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("https://localhost:%d/httpstreamer", port), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
rsp, err := client.Transport.(*http3.RoundTripper).RoundTripOpt(req, http3.RoundTripOpt{DontCloseRequestStream: true})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
@ -431,7 +443,11 @@ var _ = Describe("HTTP tests", func() {
|
|||
})
|
||||
|
||||
expectedEnd := time.Now().Add(deadlineDelay)
|
||||
resp, err := client.Post("https://localhost:"+port+"/read-deadline", "text/plain", neverEnding('a'))
|
||||
resp, err := client.Post(
|
||||
fmt.Sprintf("https://localhost:%d/read-deadline", port),
|
||||
"text/plain",
|
||||
neverEnding('a'),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resp.StatusCode).To(Equal(200))
|
||||
|
||||
|
@ -453,7 +469,7 @@ var _ = Describe("HTTP tests", func() {
|
|||
|
||||
expectedEnd := time.Now().Add(deadlineDelay)
|
||||
|
||||
resp, err := client.Get("https://localhost:" + port + "/write-deadline")
|
||||
resp, err := client.Get(fmt.Sprintf("https://localhost:%d/write-deadline", port))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(resp.StatusCode).To(Equal(200))
|
||||
|
||||
|
|
|
@ -2,9 +2,11 @@ package self_test
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"net"
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
|
@ -209,4 +211,67 @@ var _ = Describe("Multiplexing", func() {
|
|||
})
|
||||
}
|
||||
})
|
||||
|
||||
It("sends and receives non-QUIC packets", func() {
|
||||
addr1, err := net.ResolveUDPAddr("udp", "localhost:0")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
conn1, err := net.ListenUDP("udp", addr1)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer conn1.Close()
|
||||
tr1 := &quic.Transport{Conn: conn1}
|
||||
|
||||
addr2, err := net.ResolveUDPAddr("udp", "localhost:0")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
conn2, err := net.ListenUDP("udp", addr2)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer conn2.Close()
|
||||
tr2 := &quic.Transport{Conn: conn2}
|
||||
|
||||
server, err := tr1.Listen(getTLSConfig(), getQuicConfig(nil))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
runServer(server)
|
||||
defer server.Close()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
var sentPackets, rcvdPackets atomic.Int64
|
||||
const packetLen = 128
|
||||
// send a non-QUIC packet every 100µs
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
ticker := time.NewTicker(time.Millisecond / 10)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
b := make([]byte, packetLen)
|
||||
rand.Read(b[1:]) // keep the first byte set to 0, so it's not classified as a QUIC packet
|
||||
_, err := tr1.WriteTo(b, tr2.Conn.LocalAddr())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
sentPackets.Add(1)
|
||||
}
|
||||
}()
|
||||
|
||||
// receive and count non-QUIC packets
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
for {
|
||||
b := make([]byte, 1024)
|
||||
n, addr, err := tr2.ReadNonQUICPacket(ctx, b)
|
||||
if err != nil {
|
||||
Expect(err).To(MatchError(context.Canceled))
|
||||
return
|
||||
}
|
||||
Expect(addr).To(Equal(tr1.Conn.LocalAddr()))
|
||||
Expect(n).To(Equal(packetLen))
|
||||
rcvdPackets.Add(1)
|
||||
}
|
||||
}()
|
||||
dial(tr2, server.Addr())
|
||||
Eventually(func() int64 { return sentPackets.Load() }).Should(BeNumerically(">", 10))
|
||||
Eventually(func() int64 { return rcvdPackets.Load() }).Should(BeNumerically(">=", sentPackets.Load()*4/5))
|
||||
})
|
||||
})
|
||||
|
|
|
@ -56,7 +56,7 @@ var _ = Describe("TLS session resumption", func() {
|
|||
context.Background(),
|
||||
fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port),
|
||||
tlsConf,
|
||||
nil,
|
||||
getQuicConfig(nil),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
var sessionKey string
|
||||
|
@ -71,7 +71,7 @@ var _ = Describe("TLS session resumption", func() {
|
|||
context.Background(),
|
||||
fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port),
|
||||
tlsConf,
|
||||
nil,
|
||||
getQuicConfig(nil),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(gets).To(Receive(Equal(sessionKey)))
|
||||
|
@ -85,7 +85,7 @@ var _ = Describe("TLS session resumption", func() {
|
|||
It("doesn't use session resumption, if the config disables it", func() {
|
||||
sConf := getTLSConfig()
|
||||
sConf.SessionTicketsDisabled = true
|
||||
server, err := quic.ListenAddr("localhost:0", sConf, nil)
|
||||
server, err := quic.ListenAddr("localhost:0", sConf, getQuicConfig(nil))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer server.Close()
|
||||
|
||||
|
@ -98,7 +98,7 @@ var _ = Describe("TLS session resumption", func() {
|
|||
context.Background(),
|
||||
fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port),
|
||||
tlsConf,
|
||||
nil,
|
||||
getQuicConfig(nil),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Consistently(puts).ShouldNot(Receive())
|
||||
|
@ -114,7 +114,55 @@ var _ = Describe("TLS session resumption", func() {
|
|||
context.Background(),
|
||||
fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port),
|
||||
tlsConf,
|
||||
nil,
|
||||
getQuicConfig(nil),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(conn.ConnectionState().TLS.DidResume).To(BeFalse())
|
||||
|
||||
serverConn, err = server.Accept(context.Background())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(serverConn.ConnectionState().TLS.DidResume).To(BeFalse())
|
||||
})
|
||||
|
||||
It("doesn't use session resumption, if the config returned by GetConfigForClient disables it", func() {
|
||||
sConf := &tls.Config{
|
||||
GetConfigForClient: func(*tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
conf := getTLSConfig()
|
||||
conf.SessionTicketsDisabled = true
|
||||
return conf, nil
|
||||
},
|
||||
}
|
||||
|
||||
server, err := quic.ListenAddr("localhost:0", sConf, getQuicConfig(nil))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer server.Close()
|
||||
|
||||
gets := make(chan string, 100)
|
||||
puts := make(chan string, 100)
|
||||
cache := newClientSessionCache(tls.NewLRUClientSessionCache(10), gets, puts)
|
||||
tlsConf := getTLSClientConfig()
|
||||
tlsConf.ClientSessionCache = cache
|
||||
conn, err := quic.DialAddr(
|
||||
context.Background(),
|
||||
fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port),
|
||||
tlsConf,
|
||||
getQuicConfig(nil),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Consistently(puts).ShouldNot(Receive())
|
||||
Expect(conn.ConnectionState().TLS.DidResume).To(BeFalse())
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
serverConn, err := server.Accept(ctx)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(serverConn.ConnectionState().TLS.DidResume).To(BeFalse())
|
||||
|
||||
conn, err = quic.DialAddr(
|
||||
context.Background(),
|
||||
fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port),
|
||||
tlsConf,
|
||||
getQuicConfig(nil),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(conn.ConnectionState().TLS.DidResume).To(BeFalse())
|
||||
|
|
|
@ -802,4 +802,116 @@ var _ = Describe("0-RTT", func() {
|
|||
Expect(len(zeroRTTPackets)).To(BeNumerically(">", 10))
|
||||
Expect(zeroRTTPackets[0]).To(Equal(protocol.PacketNumber(0)))
|
||||
})
|
||||
|
||||
It("sends 0-RTT datagrams", func() {
|
||||
tlsConf, clientTLSConf := dialAndReceiveSessionTicket(getQuicConfig(&quic.Config{
|
||||
EnableDatagrams: true,
|
||||
}))
|
||||
|
||||
tracer := newPacketTracer()
|
||||
ln, err := quic.ListenAddrEarly(
|
||||
"localhost:0",
|
||||
tlsConf,
|
||||
getQuicConfig(&quic.Config{
|
||||
Allow0RTT: true,
|
||||
EnableDatagrams: true,
|
||||
Tracer: newTracer(tracer),
|
||||
}),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer ln.Close()
|
||||
|
||||
proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port)
|
||||
defer proxy.Close()
|
||||
|
||||
// second connection
|
||||
sentMessage := GeneratePRData(100)
|
||||
var receivedMessage []byte
|
||||
received := make(chan struct{})
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
defer close(received)
|
||||
conn, err := ln.Accept(context.Background())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
receivedMessage, err = conn.ReceiveMessage(context.Background())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(conn.ConnectionState().Used0RTT).To(BeTrue())
|
||||
}()
|
||||
conn, err := quic.DialAddrEarly(
|
||||
context.Background(),
|
||||
fmt.Sprintf("localhost:%d", proxy.LocalPort()),
|
||||
clientTLSConf,
|
||||
getQuicConfig(&quic.Config{
|
||||
EnableDatagrams: true,
|
||||
}),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(conn.ConnectionState().SupportsDatagrams).To(BeTrue())
|
||||
Expect(conn.SendMessage(sentMessage)).To(Succeed())
|
||||
<-conn.HandshakeComplete()
|
||||
<-received
|
||||
|
||||
Expect(conn.ConnectionState().Used0RTT).To(BeTrue())
|
||||
Expect(receivedMessage).To(Equal(sentMessage))
|
||||
num0RTT := atomic.LoadUint32(num0RTTPackets)
|
||||
fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT)
|
||||
Expect(num0RTT).ToNot(BeZero())
|
||||
zeroRTTPackets := get0RTTPackets(tracer.getRcvdLongHeaderPackets())
|
||||
Expect(zeroRTTPackets).To(HaveLen(1))
|
||||
Expect(conn.CloseWithError(0, "")).To(Succeed())
|
||||
})
|
||||
|
||||
It("rejects 0-RTT datagrams when the server doesn't support datagrams anymore", func() {
|
||||
tlsConf, clientTLSConf := dialAndReceiveSessionTicket(getQuicConfig(&quic.Config{
|
||||
EnableDatagrams: true,
|
||||
}))
|
||||
|
||||
tracer := newPacketTracer()
|
||||
ln, err := quic.ListenAddrEarly(
|
||||
"localhost:0",
|
||||
tlsConf,
|
||||
getQuicConfig(&quic.Config{
|
||||
Allow0RTT: true,
|
||||
EnableDatagrams: false,
|
||||
Tracer: newTracer(tracer),
|
||||
}),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer ln.Close()
|
||||
|
||||
proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port)
|
||||
defer proxy.Close()
|
||||
|
||||
// second connection
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
conn, err := ln.Accept(context.Background())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
_, err = conn.ReceiveMessage(context.Background())
|
||||
Expect(err.Error()).To(Equal("datagram support disabled"))
|
||||
<-conn.HandshakeComplete()
|
||||
Expect(conn.ConnectionState().Used0RTT).To(BeFalse())
|
||||
}()
|
||||
conn, err := quic.DialAddrEarly(
|
||||
context.Background(),
|
||||
fmt.Sprintf("localhost:%d", proxy.LocalPort()),
|
||||
clientTLSConf,
|
||||
getQuicConfig(&quic.Config{
|
||||
EnableDatagrams: true,
|
||||
}),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
// the client can temporarily send datagrams but the server doesn't process them.
|
||||
Expect(conn.ConnectionState().SupportsDatagrams).To(BeTrue())
|
||||
Expect(conn.SendMessage(make([]byte, 100))).To(Succeed())
|
||||
<-conn.HandshakeComplete()
|
||||
|
||||
Expect(conn.ConnectionState().SupportsDatagrams).To(BeFalse())
|
||||
Expect(conn.ConnectionState().Used0RTT).To(BeFalse())
|
||||
num0RTT := atomic.LoadUint32(num0RTTPackets)
|
||||
fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT)
|
||||
Expect(num0RTT).ToNot(BeZero())
|
||||
Expect(get0RTTPackets(tracer.getRcvdLongHeaderPackets())).To(BeEmpty())
|
||||
Expect(conn.CloseWithError(0, "")).To(Succeed())
|
||||
})
|
||||
})
|
||||
|
|
|
@ -939,4 +939,119 @@ var _ = Describe("0-RTT", func() {
|
|||
)
|
||||
Expect(restored).To(BeTrue())
|
||||
})
|
||||
|
||||
It("sends 0-RTT datagrams", func() {
|
||||
tlsConf := getTLSConfig()
|
||||
clientTLSConf := getTLSClientConfig()
|
||||
dialAndReceiveSessionTicket(tlsConf, getQuicConfig(&quic.Config{
|
||||
EnableDatagrams: true,
|
||||
}), clientTLSConf)
|
||||
|
||||
tracer := newPacketTracer()
|
||||
ln, err := quic.ListenAddrEarly(
|
||||
"localhost:0",
|
||||
tlsConf,
|
||||
getQuicConfig(&quic.Config{
|
||||
Allow0RTT: true,
|
||||
EnableDatagrams: true,
|
||||
Tracer: newTracer(tracer),
|
||||
}),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer ln.Close()
|
||||
proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port)
|
||||
defer proxy.Close()
|
||||
|
||||
// second connection
|
||||
sentMessage := GeneratePRData(100)
|
||||
var receivedMessage []byte
|
||||
received := make(chan struct{})
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
defer close(received)
|
||||
conn, err := ln.Accept(context.Background())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
receivedMessage, err = conn.ReceiveMessage(context.Background())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(conn.ConnectionState().Used0RTT).To(BeTrue())
|
||||
}()
|
||||
conn, err := quic.DialAddrEarly(
|
||||
context.Background(),
|
||||
fmt.Sprintf("localhost:%d", proxy.LocalPort()),
|
||||
clientTLSConf,
|
||||
getQuicConfig(&quic.Config{
|
||||
EnableDatagrams: true,
|
||||
}),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(conn.ConnectionState().SupportsDatagrams).To(BeTrue())
|
||||
Expect(conn.SendMessage(sentMessage)).To(Succeed())
|
||||
<-conn.HandshakeComplete()
|
||||
<-received
|
||||
|
||||
Expect(conn.ConnectionState().Used0RTT).To(BeTrue())
|
||||
Expect(receivedMessage).To(Equal(sentMessage))
|
||||
num0RTT := atomic.LoadUint32(num0RTTPackets)
|
||||
fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT)
|
||||
Expect(num0RTT).ToNot(BeZero())
|
||||
zeroRTTPackets := get0RTTPackets(tracer.getRcvdLongHeaderPackets())
|
||||
Expect(zeroRTTPackets).To(HaveLen(1))
|
||||
Expect(conn.CloseWithError(0, "")).To(Succeed())
|
||||
})
|
||||
|
||||
It("rejects 0-RTT datagrams when the server doesn't support datagrams anymore", func() {
|
||||
tlsConf := getTLSConfig()
|
||||
clientTLSConf := getTLSClientConfig()
|
||||
dialAndReceiveSessionTicket(tlsConf, getQuicConfig(&quic.Config{
|
||||
EnableDatagrams: true,
|
||||
}), clientTLSConf)
|
||||
|
||||
tracer := newPacketTracer()
|
||||
ln, err := quic.ListenAddrEarly(
|
||||
"localhost:0",
|
||||
tlsConf,
|
||||
getQuicConfig(&quic.Config{
|
||||
Allow0RTT: true,
|
||||
EnableDatagrams: false,
|
||||
Tracer: newTracer(tracer),
|
||||
}),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
defer ln.Close()
|
||||
|
||||
proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port)
|
||||
defer proxy.Close()
|
||||
|
||||
// second connection
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
conn, err := ln.Accept(context.Background())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
_, err = conn.ReceiveMessage(context.Background())
|
||||
Expect(err.Error()).To(Equal("datagram support disabled"))
|
||||
<-conn.HandshakeComplete()
|
||||
Expect(conn.ConnectionState().Used0RTT).To(BeFalse())
|
||||
}()
|
||||
conn, err := quic.DialAddrEarly(
|
||||
context.Background(),
|
||||
fmt.Sprintf("localhost:%d", proxy.LocalPort()),
|
||||
clientTLSConf,
|
||||
getQuicConfig(&quic.Config{
|
||||
EnableDatagrams: true,
|
||||
}),
|
||||
)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
// the client can temporarily send datagrams but the server doesn't process them.
|
||||
Expect(conn.ConnectionState().SupportsDatagrams).To(BeTrue())
|
||||
Expect(conn.SendMessage(make([]byte, 100))).To(Succeed())
|
||||
<-conn.HandshakeComplete()
|
||||
|
||||
Expect(conn.ConnectionState().SupportsDatagrams).To(BeFalse())
|
||||
Expect(conn.ConnectionState().Used0RTT).To(BeFalse())
|
||||
num0RTT := atomic.LoadUint32(num0RTTPackets)
|
||||
fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT)
|
||||
Expect(num0RTT).ToNot(BeZero())
|
||||
Expect(get0RTTPackets(tracer.getRcvdLongHeaderPackets())).To(BeEmpty())
|
||||
Expect(conn.CloseWithError(0, "")).To(Succeed())
|
||||
})
|
||||
})
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -68,7 +69,11 @@ var _ = Describe("QUIC Proxy", func() {
|
|||
addr, err := net.ResolveUDPAddr("udp", "localhost:"+strconv.Itoa(proxy.LocalPort()))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
_, err = net.ListenUDP("udp", addr)
|
||||
Expect(err).To(MatchError(fmt.Sprintf("listen udp 127.0.0.1:%d: bind: address already in use", proxy.LocalPort())))
|
||||
if runtime.GOOS == "windows" {
|
||||
Expect(err).To(MatchError(fmt.Sprintf("listen udp 127.0.0.1:%d: bind: Only one usage of each socket address (protocol/network address/port) is normally permitted.", proxy.LocalPort())))
|
||||
} else {
|
||||
Expect(err).To(MatchError(fmt.Sprintf("listen udp 127.0.0.1:%d: bind: address already in use", proxy.LocalPort())))
|
||||
}
|
||||
Expect(proxy.Close()).To(Succeed()) // stopping is tested in the next test
|
||||
})
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@ package ackhandler
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestCrypto(t *testing.T) {
|
||||
|
|
|
@ -7,7 +7,7 @@ package ackhandler
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
)
|
||||
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
|
||||
package ackhandler
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package ackhandler -destination mock_sent_packet_tracker_test.go github.com/refraction-networking/uquic/internal/ackhandler SentPacketTracker"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package ackhandler -destination mock_sent_packet_tracker_test.go github.com/refraction-networking/uquic/internal/ackhandler SentPacketTracker"
|
||||
type SentPacketTracker = sentPacketTracker
|
||||
|
|
|
@ -3,14 +3,13 @@ package ackhandler
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"github.com/refraction-networking/uquic/internal/protocol"
|
||||
"github.com/refraction-networking/uquic/internal/utils"
|
||||
"github.com/refraction-networking/uquic/internal/wire"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
var _ = Describe("Received Packet Handler", func() {
|
||||
|
|
|
@ -4,8 +4,6 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"github.com/refraction-networking/uquic/internal/mocks"
|
||||
"github.com/refraction-networking/uquic/internal/protocol"
|
||||
"github.com/refraction-networking/uquic/internal/qerr"
|
||||
|
@ -14,6 +12,7 @@ import (
|
|||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
type customFrameHandler struct {
|
||||
|
|
|
@ -3,9 +3,9 @@ package flowcontrol
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestFlowControl(t *testing.T) {
|
||||
|
|
|
@ -31,7 +31,7 @@ func getCipherSuite(id uint16) *cipherSuite {
|
|||
case tls.TLS_CHACHA20_POLY1305_SHA256:
|
||||
return &cipherSuite{ID: tls.TLS_CHACHA20_POLY1305_SHA256, Hash: crypto.SHA256, KeyLen: 32, AEAD: aeadChaCha20Poly1305}
|
||||
case tls.TLS_AES_256_GCM_SHA384:
|
||||
return &cipherSuite{ID: tls.TLS_AES_256_GCM_SHA384, Hash: crypto.SHA256, KeyLen: 32, AEAD: aeadAESGCMTLS13}
|
||||
return &cipherSuite{ID: tls.TLS_AES_256_GCM_SHA384, Hash: crypto.SHA384, KeyLen: 32, AEAD: aeadAESGCMTLS13}
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown cypher suite: %d", id))
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
@ -358,10 +359,15 @@ func (h *cryptoSetup) getDataForSessionTicket() []byte {
|
|||
// Due to limitations in crypto/tls, it's only possible to generate a single session ticket per connection.
|
||||
// It is only valid for the server.
|
||||
func (h *cryptoSetup) GetSessionTicket() ([]byte, error) {
|
||||
if h.tlsConf.SessionTicketsDisabled {
|
||||
return nil, nil
|
||||
}
|
||||
if err := h.conn.SendSessionTicket(tls.QUICSessionTicketOptions{h.allow0RTT}); err != nil {
|
||||
if err := qtls.SendSessionTicket(h.conn, h.allow0RTT); err != nil {
|
||||
// Session tickets might be disabled by tls.Config.SessionTicketsDisabled.
|
||||
// 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.
|
||||
if strings.Contains(err.Error(), "session ticket keys unavailable") {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
ev := h.conn.NextEvent()
|
||||
|
@ -660,8 +666,9 @@ func (h *cryptoSetup) ConnectionState() ConnectionState {
|
|||
}
|
||||
|
||||
func wrapError(err error) error {
|
||||
// alert 80 is an internal error
|
||||
if alertErr := qtls.AlertError(0); errors.As(err, &alertErr) && alertErr != 80 {
|
||||
return qerr.NewLocalCryptoError(uint8(alertErr), err.Error())
|
||||
return qerr.NewLocalCryptoError(uint8(alertErr), err)
|
||||
}
|
||||
return &qerr.TransportError{ErrorCode: qerr.InternalError, ErrorMessage: err.Error()}
|
||||
}
|
||||
|
|
|
@ -18,10 +18,9 @@ import (
|
|||
"github.com/refraction-networking/uquic/internal/utils"
|
||||
"github.com/refraction-networking/uquic/internal/wire"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -7,10 +7,9 @@ import (
|
|||
|
||||
tls "github.com/refraction-networking/utls"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestHandshake(t *testing.T) {
|
||||
|
|
|
@ -17,6 +17,7 @@ var _ = Describe("Session Ticket", func() {
|
|||
InitialMaxStreamDataBidiLocal: 1,
|
||||
InitialMaxStreamDataBidiRemote: 2,
|
||||
ActiveConnectionIDLimit: 10,
|
||||
MaxDatagramFrameSize: 20,
|
||||
},
|
||||
RTT: 1337 * time.Microsecond,
|
||||
}
|
||||
|
@ -25,6 +26,7 @@ var _ = Describe("Session Ticket", func() {
|
|||
Expect(t.Parameters.InitialMaxStreamDataBidiLocal).To(BeEquivalentTo(1))
|
||||
Expect(t.Parameters.InitialMaxStreamDataBidiRemote).To(BeEquivalentTo(2))
|
||||
Expect(t.Parameters.ActiveConnectionIDLimit).To(BeEquivalentTo(10))
|
||||
Expect(t.Parameters.MaxDatagramFrameSize).To(BeEquivalentTo(20))
|
||||
Expect(t.RTT).To(Equal(1337 * time.Microsecond))
|
||||
})
|
||||
|
||||
|
|
|
@ -13,9 +13,9 @@ import (
|
|||
"github.com/refraction-networking/uquic/internal/qerr"
|
||||
"github.com/refraction-networking/uquic/internal/utils"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
var _ = Describe("Updatable AEAD", func() {
|
||||
|
|
|
@ -8,9 +8,9 @@ import (
|
|||
reflect "reflect"
|
||||
time "time"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
wire "github.com/refraction-networking/uquic/internal/wire"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockReceivedPacketHandler is a mock of ReceivedPacketHandler interface.
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
reflect "reflect"
|
||||
time "time"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
ackhandler "github.com/refraction-networking/uquic/internal/ackhandler"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
wire "github.com/refraction-networking/uquic/internal/wire"
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
reflect "reflect"
|
||||
time "time"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ package mocks
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ package mocks
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
handshake "github.com/refraction-networking/uquic/internal/handshake"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
)
|
||||
|
|
|
@ -9,11 +9,12 @@ import (
|
|||
reflect "reflect"
|
||||
time "time"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
utils "github.com/refraction-networking/uquic/internal/utils"
|
||||
wire "github.com/refraction-networking/uquic/internal/wire"
|
||||
logging "github.com/refraction-networking/uquic/logging"
|
||||
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockConnectionTracer is a mock of ConnectionTracer interface.
|
||||
|
|
|
@ -8,10 +8,10 @@ import (
|
|||
net "net"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
wire "github.com/refraction-networking/uquic/internal/wire"
|
||||
logging "github.com/refraction-networking/uquic/logging"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockTracer is a mock of Tracer interface.
|
||||
|
|
|
@ -7,7 +7,7 @@ package mocks
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
)
|
||||
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
package mocks
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package mockquic -destination quic/stream.go github.com/refraction-networking/uquic Stream"
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package mockquic -destination quic/early_conn_tmp.go github.com/refraction-networking/uquic EarlyConnection && sed 's/qtls.ConnectionState/quic.ConnectionState/g' quic/early_conn_tmp.go > quic/early_conn.go && rm quic/early_conn_tmp.go && go run golang.org/x/tools/cmd/goimports -w quic/early_conn.go"
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocklogging -destination logging/tracer.go github.com/refraction-networking/uquic/logging Tracer"
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocklogging -destination logging/connection_tracer.go github.com/refraction-networking/uquic/logging ConnectionTracer"
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocks -destination short_header_sealer.go github.com/refraction-networking/uquic/internal/handshake ShortHeaderSealer"
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocks -destination short_header_opener.go github.com/refraction-networking/uquic/internal/handshake ShortHeaderOpener"
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocks -destination long_header_opener.go github.com/refraction-networking/uquic/internal/handshake LongHeaderOpener"
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocks -destination crypto_setup_tmp.go github.com/refraction-networking/uquic/internal/handshake CryptoSetup && sed -E 's~github.com/quic-go/qtls[[:alnum:]_-]*~github.com/refraction-networking/uquic/internal/qtls~g; s~qtls.ConnectionStateWith0RTT~qtls.ConnectionState~g' crypto_setup_tmp.go > crypto_setup.go && rm crypto_setup_tmp.go && go run golang.org/x/tools/cmd/goimports -w crypto_setup.go"
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocks -destination stream_flow_controller.go github.com/refraction-networking/uquic/internal/flowcontrol StreamFlowController"
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocks -destination congestion.go github.com/refraction-networking/uquic/internal/congestion SendAlgorithmWithDebugInfos"
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocks -destination connection_flow_controller.go github.com/refraction-networking/uquic/internal/flowcontrol ConnectionFlowController"
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package mockackhandler -destination ackhandler/sent_packet_handler.go github.com/refraction-networking/uquic/internal/ackhandler SentPacketHandler"
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package mockackhandler -destination ackhandler/received_packet_handler.go github.com/refraction-networking/uquic/internal/ackhandler ReceivedPacketHandler"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -package mockquic -destination quic/stream.go github.com/refraction-networking/uquic Stream"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -package mockquic -destination quic/early_conn_tmp.go github.com/refraction-networking/uquic EarlyConnection && sed 's/qtls.ConnectionState/quic.ConnectionState/g' quic/early_conn_tmp.go > quic/early_conn.go && rm quic/early_conn_tmp.go && go run golang.org/x/tools/cmd/goimports -w quic/early_conn.go"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocklogging -destination logging/tracer.go github.com/refraction-networking/uquic/logging Tracer"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocklogging -destination logging/connection_tracer.go github.com/refraction-networking/uquic/logging ConnectionTracer"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocks -destination short_header_sealer.go github.com/refraction-networking/uquic/internal/handshake ShortHeaderSealer"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocks -destination short_header_opener.go github.com/refraction-networking/uquic/internal/handshake ShortHeaderOpener"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocks -destination long_header_opener.go github.com/refraction-networking/uquic/internal/handshake LongHeaderOpener"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocks -destination crypto_setup_tmp.go github.com/refraction-networking/uquic/internal/handshake CryptoSetup && sed -E 's~github.com/quic-go/qtls[[:alnum:]_-]*~github.com/refraction-networking/uquic/internal/qtls~g; s~qtls.ConnectionStateWith0RTT~qtls.ConnectionState~g' crypto_setup_tmp.go > crypto_setup.go && rm crypto_setup_tmp.go && go run golang.org/x/tools/cmd/goimports -w crypto_setup.go"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocks -destination stream_flow_controller.go github.com/refraction-networking/uquic/internal/flowcontrol StreamFlowController"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocks -destination congestion.go github.com/refraction-networking/uquic/internal/congestion SendAlgorithmWithDebugInfos"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocks -destination connection_flow_controller.go github.com/refraction-networking/uquic/internal/flowcontrol ConnectionFlowController"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -package mockackhandler -destination ackhandler/sent_packet_handler.go github.com/refraction-networking/uquic/internal/ackhandler SentPacketHandler"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -package mockackhandler -destination ackhandler/received_packet_handler.go github.com/refraction-networking/uquic/internal/ackhandler ReceivedPacketHandler"
|
||||
|
||||
// The following command produces a warning message on OSX, however, it still generates the correct mock file.
|
||||
// See https://github.com/golang/mock/issues/339 for details.
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocktls -destination tls/client_session_cache.go crypto/tls ClientSessionCache"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocktls -destination tls/client_session_cache.go crypto/tls ClientSessionCache"
|
||||
|
|
|
@ -9,9 +9,9 @@ import (
|
|||
net "net"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
quic "github.com/refraction-networking/uquic"
|
||||
qerr "github.com/refraction-networking/uquic/internal/qerr"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockEarlyConnection is a mock of EarlyConnection interface.
|
||||
|
|
|
@ -9,9 +9,9 @@ import (
|
|||
reflect "reflect"
|
||||
time "time"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
qerr "github.com/refraction-networking/uquic/internal/qerr"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockStream is a mock of Stream interface.
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
reflect "reflect"
|
||||
time "time"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ package mocks
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ package mocks
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
)
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
tls "github.com/refraction-networking/utls"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockClientSessionCache is a mock of ClientSessionCache interface.
|
||||
|
|
|
@ -43,6 +43,21 @@ const (
|
|||
ECNCE // 11
|
||||
)
|
||||
|
||||
func (e ECN) String() string {
|
||||
switch e {
|
||||
case ECNNon:
|
||||
return "Not-ECT"
|
||||
case ECT1:
|
||||
return "ECT(1)"
|
||||
case ECT0:
|
||||
return "ECT(0)"
|
||||
case ECNCE:
|
||||
return "CE"
|
||||
default:
|
||||
return fmt.Sprintf("invalid ECN value: %d", e)
|
||||
}
|
||||
}
|
||||
|
||||
// A ByteCount in QUIC
|
||||
type ByteCount int64
|
||||
|
||||
|
|
|
@ -22,4 +22,12 @@ var _ = Describe("Protocol", func() {
|
|||
Expect(ECN(0b00000001)).To(Equal(ECT1))
|
||||
Expect(ECN(0b00000011)).To(Equal(ECNCE))
|
||||
})
|
||||
|
||||
It("has a string representation for ECN", func() {
|
||||
Expect(ECNNon.String()).To(Equal("Not-ECT"))
|
||||
Expect(ECT0.String()).To(Equal("ECT(0)"))
|
||||
Expect(ECT1.String()).To(Equal("ECT(1)"))
|
||||
Expect(ECNCE.String()).To(Equal("CE"))
|
||||
Expect(ECN(42).String()).To(Equal("invalid ECN value: 42"))
|
||||
})
|
||||
})
|
||||
|
|
|
@ -17,15 +17,16 @@ type TransportError struct {
|
|||
FrameType uint64
|
||||
ErrorCode TransportErrorCode
|
||||
ErrorMessage string
|
||||
error error // only set for local errors, sometimes
|
||||
}
|
||||
|
||||
var _ error = &TransportError{}
|
||||
|
||||
// NewLocalCryptoError create a new TransportError instance for a crypto error
|
||||
func NewLocalCryptoError(tlsAlert uint8, errorMessage string) *TransportError {
|
||||
func NewLocalCryptoError(tlsAlert uint8, err error) *TransportError {
|
||||
return &TransportError{
|
||||
ErrorCode: 0x100 + TransportErrorCode(tlsAlert),
|
||||
ErrorMessage: errorMessage,
|
||||
ErrorCode: 0x100 + TransportErrorCode(tlsAlert),
|
||||
error: err,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,6 +36,9 @@ func (e *TransportError) Error() string {
|
|||
str += fmt.Sprintf(" (frame type: %#x)", e.FrameType)
|
||||
}
|
||||
msg := e.ErrorMessage
|
||||
if len(msg) == 0 && e.error != nil {
|
||||
msg = e.error.Error()
|
||||
}
|
||||
if len(msg) == 0 {
|
||||
msg = e.ErrorCode.Message()
|
||||
}
|
||||
|
@ -48,6 +52,10 @@ func (e *TransportError) Is(target error) bool {
|
|||
return target == net.ErrClosed
|
||||
}
|
||||
|
||||
func (e *TransportError) Unwrap() error {
|
||||
return e.error
|
||||
}
|
||||
|
||||
// An ApplicationErrorCode is an application-defined error code.
|
||||
type ApplicationErrorCode uint64
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package qerr
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/refraction-networking/uquic/internal/protocol"
|
||||
|
@ -10,6 +11,12 @@ import (
|
|||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
type myError int
|
||||
|
||||
var _ error = myError(0)
|
||||
|
||||
func (e myError) Error() string { return fmt.Sprintf("my error %d", e) }
|
||||
|
||||
var _ = Describe("QUIC Errors", func() {
|
||||
Context("Transport Errors", func() {
|
||||
It("has a string representation", func() {
|
||||
|
@ -41,12 +48,20 @@ var _ = Describe("QUIC Errors", func() {
|
|||
|
||||
Context("crypto errors", func() {
|
||||
It("has a string representation for errors with a message", func() {
|
||||
err := NewLocalCryptoError(0x42, "foobar")
|
||||
Expect(err.Error()).To(Equal("CRYPTO_ERROR 0x142 (local): foobar"))
|
||||
myErr := myError(1337)
|
||||
err := NewLocalCryptoError(0x42, myErr)
|
||||
Expect(err.Error()).To(Equal("CRYPTO_ERROR 0x142 (local): my error 1337"))
|
||||
})
|
||||
|
||||
It("unwraps errors", func() {
|
||||
var myErr myError
|
||||
err := NewLocalCryptoError(0x42, myError(1337))
|
||||
Expect(errors.As(err, &myErr)).To(BeTrue())
|
||||
Expect(myErr).To(BeEquivalentTo(1337))
|
||||
})
|
||||
|
||||
It("has a string representation for errors without a message", func() {
|
||||
err := NewLocalCryptoError(0x2a, "")
|
||||
err := NewLocalCryptoError(0x2a, nil)
|
||||
Expect(err.Error()).To(Equal("CRYPTO_ERROR 0x12a (local): tls: bad certificate"))
|
||||
})
|
||||
})
|
||||
|
|
|
@ -3,10 +3,9 @@ package qtls
|
|||
import (
|
||||
"testing"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestQTLS(t *testing.T) {
|
||||
|
|
|
@ -10,13 +10,14 @@ import (
|
|||
)
|
||||
|
||||
type (
|
||||
QUICConn = tls.QUICConn
|
||||
UQUICConn = tls.UQUICConn // [UQUIC]
|
||||
QUICConfig = tls.QUICConfig
|
||||
QUICEvent = tls.QUICEvent
|
||||
QUICEventKind = tls.QUICEventKind
|
||||
QUICEncryptionLevel = tls.QUICEncryptionLevel
|
||||
AlertError = tls.AlertError
|
||||
QUICConn = tls.QUICConn
|
||||
UQUICConn = tls.UQUICConn // [UQUIC]
|
||||
QUICConfig = tls.QUICConfig
|
||||
QUICEvent = tls.QUICEvent
|
||||
QUICEventKind = tls.QUICEventKind
|
||||
QUICEncryptionLevel = tls.QUICEncryptionLevel
|
||||
QUICSessionTicketOptions = tls.QUICSessionTicketOptions
|
||||
AlertError = tls.AlertError
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -166,3 +167,9 @@ func findExtraData(extras [][]byte) []byte {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SendSessionTicket(c *QUICConn, allow0RTT bool) error {
|
||||
return c.SendSessionTicket(tls.QUICSessionTicketOptions{
|
||||
EarlyData: allow0RTT,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -74,6 +74,10 @@ func parseArbitraryLenConnectionIDs(r *bytes.Reader) (dest, src protocol.Arbitra
|
|||
return destConnID, srcConnID, nil
|
||||
}
|
||||
|
||||
func IsPotentialQUICPacket(firstByte byte) bool {
|
||||
return firstByte&0x40 > 0
|
||||
}
|
||||
|
||||
// IsLongHeaderPacket says if this is a Long Header packet
|
||||
func IsLongHeaderPacket(firstByte byte) bool {
|
||||
return firstByte&0x80 > 0
|
||||
|
|
|
@ -503,6 +503,7 @@ var _ = Describe("Transport Parameters", func() {
|
|||
MaxBidiStreamNum: protocol.StreamNum(getRandomValueUpTo(int64(protocol.MaxStreamCount))),
|
||||
MaxUniStreamNum: protocol.StreamNum(getRandomValueUpTo(int64(protocol.MaxStreamCount))),
|
||||
ActiveConnectionIDLimit: 2 + getRandomValueUpTo(math.MaxInt64-2),
|
||||
MaxDatagramFrameSize: protocol.ByteCount(getRandomValueUpTo(int64(protocol.MaxDatagramFrameSize))),
|
||||
}
|
||||
Expect(params.ValidFor0RTT(params)).To(BeTrue())
|
||||
b := params.MarshalForSessionTicket(nil)
|
||||
|
@ -515,6 +516,7 @@ var _ = Describe("Transport Parameters", func() {
|
|||
Expect(tp.MaxBidiStreamNum).To(Equal(params.MaxBidiStreamNum))
|
||||
Expect(tp.MaxUniStreamNum).To(Equal(params.MaxUniStreamNum))
|
||||
Expect(tp.ActiveConnectionIDLimit).To(Equal(params.ActiveConnectionIDLimit))
|
||||
Expect(tp.MaxDatagramFrameSize).To(Equal(params.MaxDatagramFrameSize))
|
||||
})
|
||||
|
||||
It("rejects the parameters if it can't parse them", func() {
|
||||
|
@ -540,6 +542,7 @@ var _ = Describe("Transport Parameters", func() {
|
|||
MaxBidiStreamNum: 5,
|
||||
MaxUniStreamNum: 6,
|
||||
ActiveConnectionIDLimit: 7,
|
||||
MaxDatagramFrameSize: 1000,
|
||||
}
|
||||
|
||||
BeforeEach(func() {
|
||||
|
@ -611,6 +614,16 @@ var _ = Describe("Transport Parameters", func() {
|
|||
p.ActiveConnectionIDLimit = 0
|
||||
Expect(p.ValidFor0RTT(saved)).To(BeFalse())
|
||||
})
|
||||
|
||||
It("accepts the parameters if the MaxDatagramFrameSize was increased", func() {
|
||||
p.MaxDatagramFrameSize = saved.MaxDatagramFrameSize + 1
|
||||
Expect(p.ValidFor0RTT(saved)).To(BeTrue())
|
||||
})
|
||||
|
||||
It("rejects the parameters if the MaxDatagramFrameSize reduced", func() {
|
||||
p.MaxDatagramFrameSize = saved.MaxDatagramFrameSize - 1
|
||||
Expect(p.ValidFor0RTT(saved)).To(BeFalse())
|
||||
})
|
||||
})
|
||||
|
||||
Context("client checks the parameters after successfully sending 0-RTT data", func() {
|
||||
|
@ -623,6 +636,7 @@ var _ = Describe("Transport Parameters", func() {
|
|||
MaxBidiStreamNum: 5,
|
||||
MaxUniStreamNum: 6,
|
||||
ActiveConnectionIDLimit: 7,
|
||||
MaxDatagramFrameSize: 1000,
|
||||
}
|
||||
|
||||
BeforeEach(func() {
|
||||
|
@ -699,6 +713,16 @@ var _ = Describe("Transport Parameters", func() {
|
|||
p.ActiveConnectionIDLimit = saved.ActiveConnectionIDLimit + 1
|
||||
Expect(p.ValidForUpdate(saved)).To(BeTrue())
|
||||
})
|
||||
|
||||
It("rejects the parameters if the MaxDatagramFrameSize reduced", func() {
|
||||
p.MaxDatagramFrameSize = saved.MaxDatagramFrameSize - 1
|
||||
Expect(p.ValidForUpdate(saved)).To(BeFalse())
|
||||
})
|
||||
|
||||
It("doesn't reject the parameters if the MaxDatagramFrameSize increased", func() {
|
||||
p.MaxDatagramFrameSize = saved.MaxDatagramFrameSize + 1
|
||||
Expect(p.ValidForUpdate(saved)).To(BeTrue())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -464,6 +464,10 @@ func (p *TransportParameters) MarshalForSessionTicket(b []byte) []byte {
|
|||
b = p.marshalVarintParam(b, initialMaxStreamsBidiParameterID, uint64(p.MaxBidiStreamNum))
|
||||
// initial_max_uni_streams
|
||||
b = p.marshalVarintParam(b, initialMaxStreamsUniParameterID, uint64(p.MaxUniStreamNum))
|
||||
// max_datagram_frame_size
|
||||
if p.MaxDatagramFrameSize != protocol.InvalidByteCount {
|
||||
b = p.marshalVarintParam(b, maxDatagramFrameSizeParameterID, uint64(p.MaxDatagramFrameSize))
|
||||
}
|
||||
// active_connection_id_limit
|
||||
return p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit)
|
||||
}
|
||||
|
@ -482,6 +486,9 @@ func (p *TransportParameters) UnmarshalFromSessionTicket(r *bytes.Reader) error
|
|||
|
||||
// ValidFor0RTT checks if the transport parameters match those saved in the session ticket.
|
||||
func (p *TransportParameters) ValidFor0RTT(saved *TransportParameters) bool {
|
||||
if saved.MaxDatagramFrameSize != protocol.InvalidByteCount && (p.MaxDatagramFrameSize == protocol.InvalidByteCount || p.MaxDatagramFrameSize < saved.MaxDatagramFrameSize) {
|
||||
return false
|
||||
}
|
||||
return p.InitialMaxStreamDataBidiLocal >= saved.InitialMaxStreamDataBidiLocal &&
|
||||
p.InitialMaxStreamDataBidiRemote >= saved.InitialMaxStreamDataBidiRemote &&
|
||||
p.InitialMaxStreamDataUni >= saved.InitialMaxStreamDataUni &&
|
||||
|
@ -494,6 +501,9 @@ func (p *TransportParameters) ValidFor0RTT(saved *TransportParameters) bool {
|
|||
// ValidForUpdate checks that the new transport parameters don't reduce limits after resuming a 0-RTT connection.
|
||||
// It is only used on the client side.
|
||||
func (p *TransportParameters) ValidForUpdate(saved *TransportParameters) bool {
|
||||
if saved.MaxDatagramFrameSize != protocol.InvalidByteCount && (p.MaxDatagramFrameSize == protocol.InvalidByteCount || p.MaxDatagramFrameSize < saved.MaxDatagramFrameSize) {
|
||||
return false
|
||||
}
|
||||
return p.ActiveConnectionIDLimit >= saved.ActiveConnectionIDLimit &&
|
||||
p.InitialMaxData >= saved.InitialMaxData &&
|
||||
p.InitialMaxStreamDataBidiLocal >= saved.InitialMaxStreamDataBidiLocal &&
|
||||
|
|
|
@ -40,7 +40,10 @@ func ComposeVersionNegotiation(destConnID, srcConnID protocol.ArbitraryLenConnec
|
|||
buf := bytes.NewBuffer(make([]byte, 0, expectedLen))
|
||||
r := make([]byte, 1)
|
||||
_, _ = rand.Read(r) // ignore the error here. It is not critical to have perfect random here.
|
||||
buf.WriteByte(r[0] | 0x80)
|
||||
// Setting the "QUIC bit" (0x40) is not required by the RFC,
|
||||
// but it allows clients to demultiplex QUIC with a long list of other protocols.
|
||||
// See RFC 9443 and https://mailarchive.ietf.org/arch/msg/quic/oR4kxGKY6mjtPC1CZegY1ED4beg/ for details.
|
||||
buf.WriteByte(r[0] | 0xc0)
|
||||
utils.BigEndian.WriteUint32(buf, 0) // version 0
|
||||
buf.WriteByte(uint8(destConnID.Len()))
|
||||
buf.Write(destConnID.Bytes())
|
||||
|
|
|
@ -64,6 +64,7 @@ var _ = Describe("Version Negotiation Packets", func() {
|
|||
versions := []protocol.VersionNumber{1001, 1003}
|
||||
data := ComposeVersionNegotiation(destConnID, srcConnID, versions)
|
||||
Expect(IsLongHeaderPacket(data[0])).To(BeTrue())
|
||||
Expect(data[0] & 0x40).ToNot(BeZero())
|
||||
v, err := ParseVersion(data)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(v).To(BeZero())
|
||||
|
|
|
@ -3,10 +3,9 @@ package logging
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestLogging(t *testing.T) {
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
reflect "reflect"
|
||||
time "time"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
utils "github.com/refraction-networking/uquic/internal/utils"
|
||||
wire "github.com/refraction-networking/uquic/internal/wire"
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
net "net"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
wire "github.com/refraction-networking/uquic/internal/wire"
|
||||
)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package logging
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package logging -self_package github.com/refraction-networking/uquic/logging -destination mock_connection_tracer_test.go github.com/refraction-networking/uquic/logging ConnectionTracer"
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package logging -self_package github.com/refraction-networking/uquic/logging -destination mock_tracer_test.go github.com/refraction-networking/uquic/logging Tracer"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -package logging -self_package github.com/refraction-networking/uquic/logging -destination mock_connection_tracer_test.go github.com/refraction-networking/uquic/logging ConnectionTracer"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -package logging -self_package github.com/refraction-networking/uquic/logging -destination mock_tracer_test.go github.com/refraction-networking/uquic/logging Tracer"
|
||||
|
|
|
@ -7,7 +7,7 @@ package quic
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
wire "github.com/refraction-networking/uquic/internal/wire"
|
||||
)
|
||||
|
|
|
@ -7,7 +7,7 @@ package quic
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
ipv4 "golang.org/x/net/ipv4"
|
||||
)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ package quic
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ package quic
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
handshake "github.com/refraction-networking/uquic/internal/handshake"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
)
|
||||
|
|
|
@ -7,7 +7,7 @@ package quic
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
wire "github.com/refraction-networking/uquic/internal/wire"
|
||||
)
|
||||
|
|
|
@ -7,7 +7,7 @@ package quic
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
ackhandler "github.com/refraction-networking/uquic/internal/ackhandler"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
)
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
reflect "reflect"
|
||||
time "time"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
ackhandler "github.com/refraction-networking/uquic/internal/ackhandler"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
)
|
||||
|
|
|
@ -7,7 +7,7 @@ package quic
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
ackhandler "github.com/refraction-networking/uquic/internal/ackhandler"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
qerr "github.com/refraction-networking/uquic/internal/qerr"
|
||||
|
|
|
@ -7,7 +7,7 @@ package quic
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ package quic
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
)
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
reflect "reflect"
|
||||
time "time"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockPacketConn is a mock of PacketConn interface.
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
net "net"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
qerr "github.com/refraction-networking/uquic/internal/qerr"
|
||||
)
|
||||
|
|
122
mock_raw_conn_test.go
Normal file
122
mock_raw_conn_test.go
Normal file
|
@ -0,0 +1,122 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/quic-go/quic-go (interfaces: RawConn)
|
||||
|
||||
// Package quic is a generated GoMock package.
|
||||
package quic
|
||||
|
||||
import (
|
||||
net "net"
|
||||
reflect "reflect"
|
||||
time "time"
|
||||
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockRawConn is a mock of RawConn interface.
|
||||
type MockRawConn struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockRawConnMockRecorder
|
||||
}
|
||||
|
||||
// MockRawConnMockRecorder is the mock recorder for MockRawConn.
|
||||
type MockRawConnMockRecorder struct {
|
||||
mock *MockRawConn
|
||||
}
|
||||
|
||||
// NewMockRawConn creates a new mock instance.
|
||||
func NewMockRawConn(ctrl *gomock.Controller) *MockRawConn {
|
||||
mock := &MockRawConn{ctrl: ctrl}
|
||||
mock.recorder = &MockRawConnMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockRawConn) EXPECT() *MockRawConnMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Close mocks base method.
|
||||
func (m *MockRawConn) Close() error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Close")
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Close indicates an expected call of Close.
|
||||
func (mr *MockRawConnMockRecorder) Close() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockRawConn)(nil).Close))
|
||||
}
|
||||
|
||||
// LocalAddr mocks base method.
|
||||
func (m *MockRawConn) LocalAddr() net.Addr {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "LocalAddr")
|
||||
ret0, _ := ret[0].(net.Addr)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// LocalAddr indicates an expected call of LocalAddr.
|
||||
func (mr *MockRawConnMockRecorder) LocalAddr() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LocalAddr", reflect.TypeOf((*MockRawConn)(nil).LocalAddr))
|
||||
}
|
||||
|
||||
// ReadPacket mocks base method.
|
||||
func (m *MockRawConn) ReadPacket() (receivedPacket, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ReadPacket")
|
||||
ret0, _ := ret[0].(receivedPacket)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ReadPacket indicates an expected call of ReadPacket.
|
||||
func (mr *MockRawConnMockRecorder) ReadPacket() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadPacket", reflect.TypeOf((*MockRawConn)(nil).ReadPacket))
|
||||
}
|
||||
|
||||
// SetReadDeadline mocks base method.
|
||||
func (m *MockRawConn) SetReadDeadline(arg0 time.Time) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetReadDeadline", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetReadDeadline indicates an expected call of SetReadDeadline.
|
||||
func (mr *MockRawConnMockRecorder) SetReadDeadline(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetReadDeadline", reflect.TypeOf((*MockRawConn)(nil).SetReadDeadline), arg0)
|
||||
}
|
||||
|
||||
// WritePacket mocks base method.
|
||||
func (m *MockRawConn) WritePacket(arg0 []byte, arg1 net.Addr, arg2 []byte) (int, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "WritePacket", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(int)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// WritePacket indicates an expected call of WritePacket.
|
||||
func (mr *MockRawConnMockRecorder) WritePacket(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WritePacket", reflect.TypeOf((*MockRawConn)(nil).WritePacket), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// capabilities mocks base method.
|
||||
func (m *MockRawConn) capabilities() connCapabilities {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "capabilities")
|
||||
ret0, _ := ret[0].(connCapabilities)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// capabilities indicates an expected call of capabilities.
|
||||
func (mr *MockRawConnMockRecorder) capabilities() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "capabilities", reflect.TypeOf((*MockRawConn)(nil).capabilities))
|
||||
}
|
|
@ -8,7 +8,7 @@ import (
|
|||
reflect "reflect"
|
||||
time "time"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
qerr "github.com/refraction-networking/uquic/internal/qerr"
|
||||
wire "github.com/refraction-networking/uquic/internal/wire"
|
||||
|
|
|
@ -7,7 +7,7 @@ package quic
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
handshake "github.com/refraction-networking/uquic/internal/handshake"
|
||||
)
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
net "net"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
)
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
reflect "reflect"
|
||||
time "time"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
ackhandler "github.com/refraction-networking/uquic/internal/ackhandler"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
qerr "github.com/refraction-networking/uquic/internal/qerr"
|
||||
|
|
|
@ -7,7 +7,7 @@ package quic
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ package quic
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
)
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
reflect "reflect"
|
||||
time "time"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
ackhandler "github.com/refraction-networking/uquic/internal/ackhandler"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
qerr "github.com/refraction-networking/uquic/internal/qerr"
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
wire "github.com/refraction-networking/uquic/internal/wire"
|
||||
)
|
||||
|
|
|
@ -7,7 +7,7 @@ package quic
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
wire "github.com/refraction-networking/uquic/internal/wire"
|
||||
)
|
||||
|
|
|
@ -7,7 +7,7 @@ package quic
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockTokenStore is a mock of TokenStore interface.
|
||||
|
|
|
@ -7,7 +7,7 @@ package quic
|
|||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockUnknownPacketHandler is a mock of UnknownPacketHandler interface.
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
reflect "reflect"
|
||||
time "time"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
protocol "github.com/refraction-networking/uquic/internal/protocol"
|
||||
wire "github.com/refraction-networking/uquic/internal/wire"
|
||||
)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue