use application-specific CONNECTION_CLOSE for application errors

This commit is contained in:
Marten Seemann
2019-11-08 13:46:20 +07:00
parent 914193cc9d
commit a472ac4731
4 changed files with 25 additions and 8 deletions

View File

@@ -39,6 +39,7 @@ func CryptoError(tlsAlert uint8, errorMessage string) *QuicError {
}
}
// ApplicationError creates a new QuicError instance for an application error
func ApplicationError(errorCode ErrorCode, errorMessage string) *QuicError {
return &QuicError{
ErrorCode: errorCode,
@@ -65,6 +66,11 @@ func (e *QuicError) IsCryptoError() bool {
return e.ErrorCode.isCryptoError()
}
// IsApplicationError says if this error is an application error
func (e *QuicError) IsApplicationError() bool {
return e.isApplicationError
}
// Temporary says if the error is temporary.
func (e *QuicError) Temporary() bool {
return false

View File

@@ -11,6 +11,7 @@ var _ = Describe("QUIC Transport Errors", func() {
It("has a string representation", func() {
err := Error(FlowControlError, "foobar")
Expect(err.Timeout()).To(BeFalse())
Expect(err.IsApplicationError()).To(BeFalse())
Expect(err.Error()).To(Equal("FLOW_CONTROL_ERROR: foobar"))
})
@@ -38,13 +39,17 @@ var _ = Describe("QUIC Transport Errors", func() {
It("says if an error is a crypto error", func() {
Expect(Error(FlowControlError, "").IsCryptoError()).To(BeFalse())
Expect(CryptoError(42, "").IsCryptoError()).To(BeTrue())
err := CryptoError(42, "")
Expect(err.IsCryptoError()).To(BeTrue())
Expect(err.IsApplicationError()).To(BeFalse())
})
})
Context("application errors", func() {
It("has a string representation for errors with a message", func() {
err := ApplicationError(0x42, "foobar")
Expect(err.IsApplicationError()).To(BeTrue())
Expect(err.Error()).To(Equal("Application error 0x42: foobar"))
})

View File

@@ -1023,7 +1023,7 @@ func (s *session) Close() error {
}
func (s *session) CloseWithError(code protocol.ApplicationErrorCode, desc string) error {
s.closeLocal(qerr.Error(qerr.ErrorCode(code), desc))
s.closeLocal(qerr.ApplicationError(qerr.ErrorCode(code), desc))
<-s.ctx.Done()
return nil
}
@@ -1250,8 +1250,9 @@ func (s *session) sendConnectionClose(quicErr *qerr.QuicError) ([]byte, error) {
reason = quicErr.ErrorMessage
}
packet, err := s.packer.PackConnectionClose(&wire.ConnectionCloseFrame{
ErrorCode: quicErr.ErrorCode,
ReasonPhrase: reason,
IsApplicationError: quicErr.IsApplicationError(),
ErrorCode: quicErr.ErrorCode,
ReasonPhrase: reason,
})
if err != nil {
return nil, err

View File

@@ -449,12 +449,17 @@ var _ = Describe("Session", func() {
Expect(sess.Context().Done()).To(BeClosed())
})
It("closes streams with proper error", func() {
It("closes with an error", func() {
testErr := errors.New("test error")
streamManager.EXPECT().CloseWithError(qerr.Error(0x1337, testErr.Error()))
streamManager.EXPECT().CloseWithError(qerr.ApplicationError(0x1337, testErr.Error()))
expectReplaceWithClosed()
cryptoSetup.EXPECT().Close()
packer.EXPECT().PackConnectionClose(gomock.Any()).Return(&packedPacket{}, nil)
packer.EXPECT().PackConnectionClose(gomock.Any()).DoAndReturn(func(f *wire.ConnectionCloseFrame) (*packedPacket, error) {
Expect(f.IsApplicationError).To(BeTrue())
Expect(f.ErrorCode).To(BeEquivalentTo(0x1337))
Expect(f.ReasonPhrase).To(Equal("test error"))
return &packedPacket{}, nil
})
sess.CloseWithError(0x1337, testErr.Error())
Eventually(areSessionsRunning).Should(BeFalse())
Expect(sess.Context().Done()).To(BeClosed())
@@ -1203,7 +1208,7 @@ var _ = Describe("Session", func() {
defer GinkgoRecover()
cryptoSetup.EXPECT().RunHandshake().MaxTimes(1)
err := sess.run()
Expect(err).To(MatchError(qerr.Error(0x1337, testErr.Error())))
Expect(err).To(MatchError(qerr.ApplicationError(0x1337, testErr.Error())))
close(done)
}()
streamManager.EXPECT().CloseWithError(gomock.Any())