diff --git a/h2quic/server_test.go b/h2quic/server_test.go index 0d351f820..0de87bc1e 100644 --- a/h2quic/server_test.go +++ b/h2quic/server_test.go @@ -286,7 +286,7 @@ var _ = Describe("H2 server", func() { 'f', 'o', 'o', 'b', 'a', 'r', }) err := s.handleRequest(session, headerStream, &sync.Mutex{}, hpackDecoder, h2framer) - Expect(err).To(MatchError("ProtocolViolation: expected a header frame")) + Expect(err).To(MatchError("PROTOCOL_VIOLATION: expected a header frame")) }) It("Cancels the request context when the datstream is closed", func() { diff --git a/internal/ackhandler/sent_packet_handler_test.go b/internal/ackhandler/sent_packet_handler_test.go index e6cd8d5eb..10d6d18ea 100644 --- a/internal/ackhandler/sent_packet_handler_test.go +++ b/internal/ackhandler/sent_packet_handler_test.go @@ -161,7 +161,7 @@ var _ = Describe("SentPacketHandler", func() { It("rejects ACKs with a too high LargestAcked packet number", func() { ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 0, Largest: 9999}}} err := handler.ReceivedAck(ack, 1, protocol.Encryption1RTT, time.Now()) - Expect(err).To(MatchError("ProtocolViolation: Received ACK for an unsent packet")) + Expect(err).To(MatchError("PROTOCOL_VIOLATION: Received ACK for an unsent packet")) Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(10))) }) @@ -809,7 +809,7 @@ var _ = Describe("SentPacketHandler", func() { }) ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 13, Largest: 13}}} err := handler.ReceivedAck(ack, 1, protocol.EncryptionHandshake, time.Now()) - Expect(err).To(MatchError("ProtocolViolation: Received ACK for an unsent packet")) + Expect(err).To(MatchError("PROTOCOL_VIOLATION: Received ACK for an unsent packet")) }) It("deletes crypto packets when the handshake completes", func() { diff --git a/internal/flowcontrol/stream_flow_controller_test.go b/internal/flowcontrol/stream_flow_controller_test.go index b9fc1fe8b..ac2dea671 100644 --- a/internal/flowcontrol/stream_flow_controller_test.go +++ b/internal/flowcontrol/stream_flow_controller_test.go @@ -98,7 +98,7 @@ var _ = Describe("Stream Flow controller", func() { }) It("detects a flow control violation", func() { - Expect(controller.UpdateHighestReceived(receiveWindow+1, false)).To(MatchError("FlowControlError: Received 0x10001 bytes on stream 10, allowed 0x10000 bytes")) + Expect(controller.UpdateHighestReceived(receiveWindow+1, false)).To(MatchError("FLOW_CONTROL_ERROR: Received 0x10001 bytes on stream 10, allowed 0x10000 bytes")) }) It("accepts a final offset higher than the highest received", func() { @@ -109,7 +109,7 @@ var _ = Describe("Stream Flow controller", func() { It("errors when receiving a final offset smaller than the highest offset received so far", func() { controller.UpdateHighestReceived(0x100, false) - Expect(controller.UpdateHighestReceived(0xff, true)).To(MatchError("FinalSizeError: Received final offset 0xff for stream 10, but already received offset 0x100 before")) + Expect(controller.UpdateHighestReceived(0xff, true)).To(MatchError("FINAL_SIZE_ERROR: Received final offset 0xff for stream 10, but already received offset 0x100 before")) }) It("accepts delayed data after receiving a final offset", func() { @@ -119,7 +119,7 @@ var _ = Describe("Stream Flow controller", func() { It("errors when receiving a higher offset after receiving a final offset", func() { Expect(controller.UpdateHighestReceived(0x200, true)).To(Succeed()) - Expect(controller.UpdateHighestReceived(0x250, false)).To(MatchError("FinalSizeError: Received offset 0x250 for stream 10. Final offset was already received at 0x200")) + Expect(controller.UpdateHighestReceived(0x250, false)).To(MatchError("FINAL_SIZE_ERROR: Received offset 0x250 for stream 10. Final offset was already received at 0x200")) }) It("accepts duplicate final offsets", func() { @@ -130,7 +130,7 @@ var _ = Describe("Stream Flow controller", func() { It("errors when receiving inconsistent final offsets", func() { Expect(controller.UpdateHighestReceived(0x200, true)).To(Succeed()) - Expect(controller.UpdateHighestReceived(0x201, true)).To(MatchError("FinalSizeError: Received inconsistent final offset for stream 10 (old: 0x200, new: 0x201 bytes)")) + Expect(controller.UpdateHighestReceived(0x201, true)).To(MatchError("FINAL_SIZE_ERROR: Received inconsistent final offset for stream 10 (old: 0x200, new: 0x201 bytes)")) }) It("tells the connection flow controller when a stream is abandoned", func() { diff --git a/internal/qerr/error_codes.go b/internal/qerr/error_codes.go index b7f218473..51be73f47 100644 --- a/internal/qerr/error_codes.go +++ b/internal/qerr/error_codes.go @@ -1,11 +1,11 @@ package qerr -// The error codes defined by QUIC -// Remember to run `go generate ./...` whenever the error codes change. -// This uses the Go stringer tool, which can be installed by running -// go get -u golang.org/x/tools/cmd/stringer +import "fmt" -//go:generate stringer -type=ErrorCode +// ErrorCode can be used as a normal error without reason. +type ErrorCode uint16 + +// The error codes defined by QUIC const ( NoError ErrorCode = 0x0 InternalError ErrorCode = 0x1 @@ -21,3 +21,40 @@ const ( InvalidMigration ErrorCode = 0xc CryptoError ErrorCode = 0x100 ) + +func (e ErrorCode) Error() string { + return e.String() +} + +func (e ErrorCode) String() string { + switch e { + case NoError: + return "NO_ERROR" + case InternalError: + return "INTERNAL_ERROR" + case ServerBusy: + return "SERVER_BUSY" + case FlowControlError: + return "FLOW_CONTROL_ERROR" + case StreamLimitError: + return "STREAM_LIMIT_ERROR" + case StreamStateError: + return "STREAM_STATE_ERROR" + case FinalSizeError: + return "FINAL_SIZE_ERROR" + case FrameEncodingError: + return "FRAME_ENCODING_ERROR" + case TransportParameterError: + return "TRANSPORT_PARAMETER_ERROR" + case VersionNegotiationError: + return "VERSION_NEGOTIATION_ERROR" + case ProtocolViolation: + return "PROTOCOL_VIOLATION" + case InvalidMigration: + return "INVALID_MIGRATION" + case CryptoError: + return "CRYPTO_ERROR" + default: + return fmt.Sprintf("unknown error code: %d", e) + } +} diff --git a/internal/qerr/errorcode_string.go b/internal/qerr/errorcode_string.go deleted file mode 100644 index 288ec2a4a..000000000 --- a/internal/qerr/errorcode_string.go +++ /dev/null @@ -1,28 +0,0 @@ -// Code generated by "stringer -type=ErrorCode"; DO NOT EDIT. - -package qerr - -import "strconv" - -const ( - _ErrorCode_name_0 = "NoErrorInternalErrorServerBusyFlowControlErrorStreamLimitErrorStreamStateErrorFinalSizeErrorFrameEncodingErrorTransportParameterErrorVersionNegotiationErrorProtocolViolation" - _ErrorCode_name_1 = "InvalidMigration" - _ErrorCode_name_2 = "CryptoError" -) - -var ( - _ErrorCode_index_0 = [...]uint8{0, 7, 20, 30, 46, 62, 78, 92, 110, 133, 156, 173} -) - -func (i ErrorCode) String() string { - switch { - case 0 <= i && i <= 10: - return _ErrorCode_name_0[_ErrorCode_index_0[i]:_ErrorCode_index_0[i+1]] - case i == 12: - return _ErrorCode_name_1 - case i == 256: - return _ErrorCode_name_2 - default: - return "ErrorCode(" + strconv.FormatInt(int64(i), 10) + ")" - } -} diff --git a/internal/qerr/errorcodes_test.go b/internal/qerr/errorcodes_test.go index 2caa8c3c1..da0cfb6ac 100644 --- a/internal/qerr/errorcodes_test.go +++ b/internal/qerr/errorcodes_test.go @@ -24,14 +24,17 @@ var _ = Describe("error codes", func() { filename := path.Join(path.Dir(thisfile), "error_codes.go") fileAst, err := parser.ParseFile(token.NewFileSet(), filename, nil, 0) Expect(err).NotTo(HaveOccurred()) - constSpecs := fileAst.Decls[0].(*ast.GenDecl).Specs + constSpecs := fileAst.Decls[2].(*ast.GenDecl).Specs Expect(len(constSpecs)).To(BeNumerically(">", 4)) // at time of writing for _, c := range constSpecs { - name := c.(*ast.ValueSpec).Names[0].Name valString := c.(*ast.ValueSpec).Values[0].(*ast.BasicLit).Value val, err := strconv.ParseInt(valString, 0, 64) Expect(err).NotTo(HaveOccurred()) - Expect(ErrorCode(val).String()).To(Equal(name)) + Expect(ErrorCode(val).String()).ToNot(Equal("unknown error code")) } }) + + It("has a string representation for unknown error codes", func() { + Expect(ErrorCode(1337).String()).To(Equal("unknown error code: 1337")) + }) }) diff --git a/internal/qerr/quic_error.go b/internal/qerr/quic_error.go index a6ac6fb6d..599bcd17e 100644 --- a/internal/qerr/quic_error.go +++ b/internal/qerr/quic_error.go @@ -5,13 +5,6 @@ import ( "net" ) -// ErrorCode can be used as a normal error without reason. -type ErrorCode uint16 - -func (e ErrorCode) Error() string { - return e.String() -} - // A QuicError consists of an error code plus a error reason type QuicError struct { ErrorCode ErrorCode diff --git a/internal/qerr/quic_error_test.go b/internal/qerr/quic_error_test.go index 0d082cedd..6c031933e 100644 --- a/internal/qerr/quic_error_test.go +++ b/internal/qerr/quic_error_test.go @@ -11,14 +11,14 @@ var _ = Describe("QUIC Transport Errors", func() { Context("QuicError", func() { It("has a string representation", func() { err := Error(FlowControlError, "foobar") - Expect(err.Error()).To(Equal("FlowControlError: foobar")) + Expect(err.Error()).To(Equal("FLOW_CONTROL_ERROR: foobar")) }) }) Context("ErrorCode", func() { It("works as error", func() { var err error = StreamStateError - Expect(err).To(MatchError("StreamStateError")) + Expect(err).To(MatchError("STREAM_STATE_ERROR")) }) }) diff --git a/internal/wire/frame_parser_test.go b/internal/wire/frame_parser_test.go index 87088b402..04160db63 100644 --- a/internal/wire/frame_parser_test.go +++ b/internal/wire/frame_parser_test.go @@ -273,7 +273,7 @@ var _ = Describe("Frame parsing", func() { It("errors on invalid type", func() { _, err := parser.ParseNext(bytes.NewReader([]byte{0x42}), protocol.Encryption1RTT) - Expect(err).To(MatchError("FrameEncodingError: unknown type byte 0x42")) + Expect(err).To(MatchError("FRAME_ENCODING_ERROR: unknown type byte 0x42")) }) It("errors on invalid frames", func() { diff --git a/internal/wire/stream_frame_test.go b/internal/wire/stream_frame_test.go index ce3964150..4675f71f0 100644 --- a/internal/wire/stream_frame_test.go +++ b/internal/wire/stream_frame_test.go @@ -75,7 +75,7 @@ var _ = Describe("STREAM frame", func() { data = append(data, []byte("foobar")...) r := bytes.NewReader(data) _, err := parseStreamFrame(r, versionIETFFrames) - Expect(err).To(MatchError("FrameEncodingError: stream data overflows maximum offset")) + Expect(err).To(MatchError("FRAME_ENCODING_ERROR: stream data overflows maximum offset")) }) It("errors on EOFs", func() { diff --git a/session_test.go b/session_test.go index c4f486c8c..bbb3b14c0 100644 --- a/session_test.go +++ b/session_test.go @@ -571,7 +571,7 @@ var _ = Describe("Session", func() { defer GinkgoRecover() cryptoSetup.EXPECT().RunHandshake().Do(func() { <-sess.Context().Done() }) err := sess.run() - Expect(err).To(MatchError("ProtocolViolation: empty packet")) + Expect(err).To(MatchError("PROTOCOL_VIOLATION: empty packet")) close(done) }() sessionRunner.EXPECT().retireConnectionID(gomock.Any()) @@ -1219,7 +1219,7 @@ var _ = Describe("Session", func() { InitialVersion: 13, // this must be a supported version } _, err := sess.processTransportParametersForServer(chtp.Marshal()) - Expect(err).To(MatchError("VersionNegotiationError: Client should have used the initial version")) + Expect(err).To(MatchError("VERSION_NEGOTIATION_ERROR: Client should have used the initial version")) }) }) @@ -1696,7 +1696,7 @@ var _ = Describe("Client Session", func() { Parameters: params, } _, err := sess.processTransportParametersForClient(eetp.Marshal()) - Expect(err).To(MatchError("VersionNegotiationError: current version doesn't match negotiated_version")) + Expect(err).To(MatchError("VERSION_NEGOTIATION_ERROR: current version doesn't match negotiated_version")) }) It("errors if the current version is not contained in the server's supported versions", func() { @@ -1707,7 +1707,7 @@ var _ = Describe("Client Session", func() { Parameters: params, } _, err := sess.processTransportParametersForClient(eetp.Marshal()) - Expect(err).To(MatchError("VersionNegotiationError: current version not included in the supported versions")) + Expect(err).To(MatchError("VERSION_NEGOTIATION_ERROR: current version not included in the supported versions")) }) It("errors if version negotiation was performed, but would have picked a different version based on the supported version list", func() { @@ -1725,7 +1725,7 @@ var _ = Describe("Client Session", func() { Parameters: params, } _, err := sess.processTransportParametersForClient(eetp.Marshal()) - Expect(err).To(MatchError("VersionNegotiationError: would have picked a different version")) + Expect(err).To(MatchError("VERSION_NEGOTIATION_ERROR: would have picked a different version")) }) It("doesn't error if it would have picked a different version based on the supported version list, if no version negotiation was performed", func() {