Merge pull request #2233 from lucas-clemente/connection-close-before-1rtt

don't send application-level errors before completion of the handshake
This commit is contained in:
Marten Seemann
2019-11-24 21:14:21 +07:00
committed by GitHub
3 changed files with 27 additions and 0 deletions

View File

@@ -16,6 +16,10 @@ type QuicError struct {
var _ net.Error = &QuicError{} var _ net.Error = &QuicError{}
// UserCanceledError is used if the application closes the connection
// before the handshake completes.
var UserCanceledError = &QuicError{ErrorCode: 0x15a}
// Error creates a new QuicError instance // Error creates a new QuicError instance
func Error(errorCode ErrorCode, errorMessage string) *QuicError { func Error(errorCode ErrorCode, errorMessage string) *QuicError {
return &QuicError{ return &QuicError{

View File

@@ -1282,6 +1282,10 @@ func (s *session) sendPackedPacket(packet *packedPacket) {
} }
func (s *session) sendConnectionClose(quicErr *qerr.QuicError) ([]byte, error) { func (s *session) sendConnectionClose(quicErr *qerr.QuicError) ([]byte, error) {
// don't send application errors in Initial or Handshake packets
if quicErr.IsApplicationError() && !s.handshakeComplete {
quicErr = qerr.UserCanceledError
}
var reason string var reason string
// don't send details of crypto errors // don't send details of crypto errors
if !quicErr.IsCryptoError() { if !quicErr.IsCryptoError() {

View File

@@ -427,6 +427,7 @@ var _ = Describe("Session", func() {
}) })
It("shuts down without error", func() { It("shuts down without error", func() {
sess.handshakeComplete = true
streamManager.EXPECT().CloseWithError(qerr.ApplicationError(0, "")) streamManager.EXPECT().CloseWithError(qerr.ApplicationError(0, ""))
expectReplaceWithClosed() expectReplaceWithClosed()
cryptoSetup.EXPECT().Close() cryptoSetup.EXPECT().Close()
@@ -457,6 +458,7 @@ var _ = Describe("Session", func() {
}) })
It("closes with an error", func() { It("closes with an error", func() {
sess.handshakeComplete = true
streamManager.EXPECT().CloseWithError(qerr.ApplicationError(0x1337, "test error")) streamManager.EXPECT().CloseWithError(qerr.ApplicationError(0x1337, "test error"))
expectReplaceWithClosed() expectReplaceWithClosed()
cryptoSetup.EXPECT().Close() cryptoSetup.EXPECT().Close()
@@ -472,6 +474,7 @@ var _ = Describe("Session", func() {
}) })
It("includes the frame type in transport-level close frames", func() { It("includes the frame type in transport-level close frames", func() {
sess.handshakeComplete = true
testErr := qerr.ErrorWithFrameType(0x1337, 0x42, "test error") testErr := qerr.ErrorWithFrameType(0x1337, 0x42, "test error")
streamManager.EXPECT().CloseWithError(testErr) streamManager.EXPECT().CloseWithError(testErr)
expectReplaceWithClosed() expectReplaceWithClosed()
@@ -488,6 +491,21 @@ var _ = Describe("Session", func() {
Expect(sess.Context().Done()).To(BeClosed()) Expect(sess.Context().Done()).To(BeClosed())
}) })
It("doesn't send application-level error before the handshake completes", func() {
streamManager.EXPECT().CloseWithError(qerr.ApplicationError(0x1337, "test error"))
expectReplaceWithClosed()
cryptoSetup.EXPECT().Close()
packer.EXPECT().PackConnectionClose(gomock.Any()).DoAndReturn(func(f *wire.ConnectionCloseFrame) (*packedPacket, error) {
Expect(f.IsApplicationError).To(BeFalse())
Expect(f.ErrorCode).To(BeEquivalentTo(0x15a))
Expect(f.ReasonPhrase).To(BeEmpty())
return &packedPacket{}, nil
})
sess.CloseWithError(0x1337, "test error")
Eventually(areSessionsRunning).Should(BeFalse())
Expect(sess.Context().Done()).To(BeClosed())
})
It("closes the session in order to recreate it", func() { It("closes the session in order to recreate it", func() {
streamManager.EXPECT().CloseWithError(gomock.Any()) streamManager.EXPECT().CloseWithError(gomock.Any())
sessionRunner.EXPECT().Remove(gomock.Any()) sessionRunner.EXPECT().Remove(gomock.Any())
@@ -1456,6 +1474,7 @@ var _ = Describe("Session", func() {
}() }()
Consistently(sess.Context().Done()).ShouldNot(BeClosed()) Consistently(sess.Context().Done()).ShouldNot(BeClosed())
// make the go routine return // make the go routine return
sess.handshakeComplete = true
expectReplaceWithClosed() expectReplaceWithClosed()
cryptoSetup.EXPECT().Close() cryptoSetup.EXPECT().Close()
sess.Close() sess.Close()