From 3a494d76c1b3ccf80474508e194dc5fc85d8e6a1 Mon Sep 17 00:00:00 2001 From: George Barnett Date: Thu, 24 Sep 2020 09:46:06 +0100 Subject: [PATCH] Add a location to each of 'NIOHTTP2Errors' Motivation: Without knowing where an error was thrown it can be unnecessarily difficult to work out the reasons an application ended up in an error state. Modifications: - Add a 'file' string to each of the 'NIOHTTP2Errors' denoting the file and line where an error was created - Add static methods to create errors to 'NIOHTTP2Errors' defaulting file and line, this is unfortunately necessary as defaulting file and line in the `init` makes the defaulted and non-defaulted errors indistinguishable, and the compiler will pick the one with fewest defaulted values. - Add equatable conformance manually so as to ignore 'file' - Add backing storage to errors which no longer be stored in an existential container - Add 'CustomStringConvertible' conformance to the errors using backing storage so that the 'file' is actually visible when converting the error - Deprecate the old `init`s - Fix all deprecation warnings Result: - NIOHTTP2Errors carry a 'file' with them indicating where they were created --- .../ConnectionStateMachine.swift | 76 +- .../ConnectionStreamsState.swift | 18 +- .../ReceivingGoAwayState.swift | 6 +- .../ReceivingPushPromiseState.swift | 4 +- .../SendingGoawayState.swift | 6 +- .../SendingPushPromiseState.swift | 2 +- .../HTTP2SettingsState.swift | 2 +- Sources/NIOHTTP2/ContentLengthVerifier.swift | 4 +- Sources/NIOHTTP2/DOSHeuristics.swift | 2 +- .../ConcurrentStreamBuffer.swift | 8 +- .../Frame Buffers/ControlFrameBuffer.swift | 2 +- .../OutboundFlowControlBuffer.swift | 4 +- .../NIOHTTP2/HPACKHeaders+Validation.swift | 16 +- Sources/NIOHTTP2/HTTP2ChannelHandler.swift | 46 +- Sources/NIOHTTP2/HTTP2Error.swift | 1207 ++++++++++++++++- Sources/NIOHTTP2/HTTP2FlowControlWindow.swift | 8 +- Sources/NIOHTTP2/HTTP2FrameParser.swift | 12 +- Sources/NIOHTTP2/HTTP2PipelineHelpers.swift | 2 +- Sources/NIOHTTP2/HTTP2StreamChannel.swift | 4 +- Sources/NIOHTTP2/HTTP2StreamMultiplexer.swift | 2 +- Sources/NIOHTTP2/HTTP2ToHTTP1Codec.swift | 10 +- Sources/NIOHTTP2/StreamStateMachine.swift | 24 +- Tests/LinuxMain.swift | 1 + .../CompoundOutboundBufferTest.swift | 12 +- .../ConcurrentStreamBufferTest.swift | 10 +- .../ConnectionStateMachineTests.swift | 2 +- .../ControlFrameBufferTests.swift | 2 +- .../HTTP2ErrorTests+XCTest.swift | 35 + Tests/NIOHTTP2Tests/HTTP2ErrorTests.swift | 236 ++++ ...P2FramePayloadStreamMultiplexerTests.swift | 8 +- .../HTTP2FramePayloadToHTTP1CodecTests.swift | 30 +- .../OutboundFlowControlBufferTests.swift | 6 +- ...eClientServerFramePayloadStreamTests.swift | 24 +- 33 files changed, 1598 insertions(+), 233 deletions(-) create mode 100644 Tests/NIOHTTP2Tests/HTTP2ErrorTests+XCTest.swift create mode 100644 Tests/NIOHTTP2Tests/HTTP2ErrorTests.swift diff --git a/Sources/NIOHTTP2/ConnectionStateMachine/ConnectionStateMachine.swift b/Sources/NIOHTTP2/ConnectionStateMachine/ConnectionStateMachine.swift index 7fccd7ec..1351f3a8 100644 --- a/Sources/NIOHTTP2/ConnectionStateMachine/ConnectionStateMachine.swift +++ b/Sources/NIOHTTP2/ConnectionStateMachine/ConnectionStateMachine.swift @@ -618,7 +618,7 @@ extension HTTP2ConnectionStateMachine { } case .fullyQuiesced: - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.IOOnClosedConnection(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.ioOnClosedConnection(), type: .protocolError), effect: nil) case .modifying: preconditionFailure("Must not be left in modifying state") @@ -677,10 +677,10 @@ extension HTTP2ConnectionStateMachine { case .idle, .prefaceSent, .quiescingPrefaceSent: // If we're still waiting for the remote preface, they are not allowed to send us a HEADERS frame yet! - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.MissingPreface(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.missingPreface(), type: .protocolError), effect: nil) case .fullyQuiesced: - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.IOOnClosedConnection(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.ioOnClosedConnection(), type: .protocolError), effect: nil) case .modifying: preconditionFailure("Must not be left in modifying state") @@ -737,10 +737,10 @@ extension HTTP2ConnectionStateMachine { case .idle, .prefaceReceived, .quiescingPrefaceReceived: // If we're still waiting for the local preface, we are not allowed to send a HEADERS frame yet! - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.MissingPreface(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.missingPreface(), type: .protocolError), effect: nil) case .fullyQuiesced: - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.IOOnClosedConnection(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.ioOnClosedConnection(), type: .protocolError), effect: nil) case .modifying: preconditionFailure("Must not be left in modifying state") @@ -797,10 +797,10 @@ extension HTTP2ConnectionStateMachine { case .idle, .prefaceSent, .quiescingPrefaceSent: // If we're still waiting for the remote preface, we are not allowed to receive a DATA frame yet! - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.MissingPreface(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.missingPreface(), type: .protocolError), effect: nil) case .fullyQuiesced: - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.IOOnClosedConnection(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.ioOnClosedConnection(), type: .protocolError), effect: nil) case .modifying: preconditionFailure("Must not be left in modifying state") @@ -857,10 +857,10 @@ extension HTTP2ConnectionStateMachine { case .idle, .prefaceReceived, .quiescingPrefaceReceived: // If we're still waiting for the local preface, we are not allowed to send a DATA frame yet! - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.MissingPreface(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.missingPreface(), type: .protocolError), effect: nil) case .fullyQuiesced: - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.IOOnClosedConnection(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.ioOnClosedConnection(), type: .protocolError), effect: nil) case .modifying: preconditionFailure("Must not be left in modifying state") @@ -876,10 +876,10 @@ extension HTTP2ConnectionStateMachine { return StateMachineResultWithEffect(result: .succeed, effect: nil) case .idle, .prefaceSent, .quiescingPrefaceSent: - return StateMachineResultWithEffect(result: .connectionError(underlyingError: NIOHTTP2Errors.MissingPreface(), type: .protocolError), effect: nil) + return StateMachineResultWithEffect(result: .connectionError(underlyingError: NIOHTTP2Errors.missingPreface(), type: .protocolError), effect: nil) case .fullyQuiesced: - return StateMachineResultWithEffect(result: .connectionError(underlyingError: NIOHTTP2Errors.IOOnClosedConnection(), type: .protocolError), effect: nil) + return StateMachineResultWithEffect(result: .connectionError(underlyingError: NIOHTTP2Errors.ioOnClosedConnection(), type: .protocolError), effect: nil) case .modifying: preconditionFailure("Must not be left in modifying state") @@ -895,10 +895,10 @@ extension HTTP2ConnectionStateMachine { return .init(result: .succeed, effect: nil) case .idle, .prefaceReceived, .quiescingPrefaceReceived: - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.MissingPreface(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.missingPreface(), type: .protocolError), effect: nil) case .fullyQuiesced: - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.IOOnClosedConnection(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.ioOnClosedConnection(), type: .protocolError), effect: nil) case .modifying: preconditionFailure("Must not be left in modifying state") @@ -955,10 +955,10 @@ extension HTTP2ConnectionStateMachine { case .idle, .prefaceSent, .quiescingPrefaceSent: // We're waiting for the remote preface. - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.MissingPreface(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.missingPreface(), type: .protocolError), effect: nil) case .fullyQuiesced: - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.IOOnClosedConnection(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.ioOnClosedConnection(), type: .protocolError), effect: nil) case .modifying: preconditionFailure("Must not be left in modifying state") @@ -1015,10 +1015,10 @@ extension HTTP2ConnectionStateMachine { case .idle, .prefaceReceived, .quiescingPrefaceReceived: // We're waiting for the local preface. - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.MissingPreface(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.missingPreface(), type: .protocolError), effect: nil) case .fullyQuiesced: - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.IOOnClosedConnection(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.ioOnClosedConnection(), type: .protocolError), effect: nil) case .modifying: preconditionFailure("Must not be left in modifying state") @@ -1083,10 +1083,10 @@ extension HTTP2ConnectionStateMachine { case .idle, .prefaceSent, .quiescingPrefaceSent: // We're waiting for the remote preface. - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.MissingPreface(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.missingPreface(), type: .protocolError), effect: nil) case .fullyQuiesced: - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.IOOnClosedConnection(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.ioOnClosedConnection(), type: .protocolError), effect: nil) case .modifying: preconditionFailure("Must not be left in modifying state") @@ -1118,7 +1118,7 @@ extension HTTP2ConnectionStateMachine { case .remotelyQuiesced, .bothQuiescing: // We have been quiesced, and may not create new streams. - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.CreatedStreamAfterGoaway(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.createdStreamAfterGoaway(), type: .protocolError), effect: nil) case .quiescingPrefaceSent(var state): return self.avoidingStateMachineCoW { newState in @@ -1129,10 +1129,10 @@ extension HTTP2ConnectionStateMachine { case .idle, .prefaceReceived, .quiescingPrefaceReceived: // We're waiting for the local preface. - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.MissingPreface(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.missingPreface(), type: .protocolError), effect: nil) case .fullyQuiesced: - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.IOOnClosedConnection(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.ioOnClosedConnection(), type: .protocolError), effect: nil) case .modifying: preconditionFailure("Must not be left in modifying state") @@ -1150,10 +1150,10 @@ extension HTTP2ConnectionStateMachine { case .idle, .prefaceSent, .quiescingPrefaceSent: // We're waiting for the remote preface. - return (.init(result: .connectionError(underlyingError: NIOHTTP2Errors.MissingPreface(), type: .protocolError), effect: nil), .nothing) + return (.init(result: .connectionError(underlyingError: NIOHTTP2Errors.missingPreface(), type: .protocolError), effect: nil), .nothing) case .fullyQuiesced: - return (.init(result: .connectionError(underlyingError: NIOHTTP2Errors.IOOnClosedConnection(), type: .protocolError), effect: nil), .nothing) + return (.init(result: .connectionError(underlyingError: NIOHTTP2Errors.ioOnClosedConnection(), type: .protocolError), effect: nil), .nothing) case .modifying: preconditionFailure("Must not be left in modifying state") @@ -1171,10 +1171,10 @@ extension HTTP2ConnectionStateMachine { case .idle, .prefaceReceived, .quiescingPrefaceReceived: // We're waiting for the local preface. - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.MissingPreface(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.missingPreface(), type: .protocolError), effect: nil) case .fullyQuiesced: - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.IOOnClosedConnection(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.ioOnClosedConnection(), type: .protocolError), effect: nil) case .modifying: preconditionFailure("Must not be left in modifying state") @@ -1240,7 +1240,7 @@ extension HTTP2ConnectionStateMachine { case .idle, .prefaceSent, .quiescingPrefaceSent: // We're waiting for the preface. - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.MissingPreface(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.missingPreface(), type: .protocolError), effect: nil) case .fullyQuiesced(var state): return self.avoidingStateMachineCoW { newState in @@ -1313,7 +1313,7 @@ extension HTTP2ConnectionStateMachine { case .idle, .prefaceReceived, .quiescingPrefaceReceived: // We're waiting for the preface. - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.MissingPreface(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.missingPreface(), type: .protocolError), effect: nil) case .fullyQuiesced(var state): return self.avoidingStateMachineCoW { newState in @@ -1375,10 +1375,10 @@ extension HTTP2ConnectionStateMachine { case .idle, .prefaceSent, .quiescingPrefaceSent: // We're waiting for the preface. - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.MissingPreface(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.missingPreface(), type: .protocolError), effect: nil) case .fullyQuiesced: - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.IOOnClosedConnection(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.ioOnClosedConnection(), type: .protocolError), effect: nil) case .modifying: preconditionFailure("Must not be left in modifying state") @@ -1432,10 +1432,10 @@ extension HTTP2ConnectionStateMachine { case .idle, .prefaceReceived, .quiescingPrefaceReceived: // We're waiting for the preface. - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.MissingPreface(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.missingPreface(), type: .protocolError), effect: nil) case .fullyQuiesced: - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.IOOnClosedConnection(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.ioOnClosedConnection(), type: .protocolError), effect: nil) case .modifying: preconditionFailure("Must not be left in modifying state") @@ -1521,7 +1521,7 @@ extension HTTP2ConnectionStateMachine { } case .fullyQuiesced: - return (.init(result: .connectionError(underlyingError: NIOHTTP2Errors.IOOnClosedConnection(), type: .protocolError), effect: nil), .nothing) + return (.init(result: .connectionError(underlyingError: NIOHTTP2Errors.ioOnClosedConnection(), type: .protocolError), effect: nil), .nothing) case .modifying: preconditionFailure("Must not be left in modifying state") @@ -1561,10 +1561,10 @@ extension HTTP2ConnectionStateMachine { } case .idle, .prefaceSent, .prefaceReceived, .quiescingPrefaceReceived, .quiescingPrefaceSent: - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.ReceivedBadSettings(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.receivedBadSettings(), type: .protocolError), effect: nil) case .fullyQuiesced: - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.IOOnClosedConnection(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.ioOnClosedConnection(), type: .protocolError), effect: nil) case .modifying: preconditionFailure("Must not be left in modifying state") @@ -1581,15 +1581,15 @@ extension HTTP2ConnectionStateMachine { switch setting.parameter { case .enablePush: guard setting._value == 0 || setting._value == 1 else { - return .connectionError(underlyingError: NIOHTTP2Errors.InvalidSetting(setting: setting), type: .protocolError) + return .connectionError(underlyingError: NIOHTTP2Errors.invalidSetting(setting: setting), type: .protocolError) } case .initialWindowSize: guard setting._value <= HTTP2FlowControlWindow.maxSize else { - return .connectionError(underlyingError: NIOHTTP2Errors.InvalidSetting(setting: setting), type: .flowControlError) + return .connectionError(underlyingError: NIOHTTP2Errors.invalidSetting(setting: setting), type: .flowControlError) } case .maxFrameSize: guard setting._value >= (1 << 14) && setting._value <= ((1 << 24) - 1) else { - return .connectionError(underlyingError: NIOHTTP2Errors.InvalidSetting(setting: setting), type: .protocolError) + return .connectionError(underlyingError: NIOHTTP2Errors.invalidSetting(setting: setting), type: .protocolError) } default: // All other settings have unrestricted ranges. diff --git a/Sources/NIOHTTP2/ConnectionStateMachine/ConnectionStreamsState.swift b/Sources/NIOHTTP2/ConnectionStateMachine/ConnectionStreamsState.swift index 58117c89..c91a7d5b 100644 --- a/Sources/NIOHTTP2/ConnectionStateMachine/ConnectionStreamsState.swift +++ b/Sources/NIOHTTP2/ConnectionStateMachine/ConnectionStreamsState.swift @@ -228,15 +228,15 @@ struct ConnectionStreamState { /// Adjusts the stream state to reserve a client stream ID. mutating func reserveClientStreamID(_ streamID: HTTP2StreamID) throws { guard self.clientStreamCount < self.maxClientInitiatedStreams else { - throw NIOHTTP2Errors.MaxStreamsViolation() + throw NIOHTTP2Errors.maxStreamsViolation() } guard streamID > self.lastClientStreamID else { - throw NIOHTTP2Errors.StreamIDTooSmall() + throw NIOHTTP2Errors.streamIDTooSmall() } guard streamID.mayBeInitiatedBy(.client) else { - throw NIOHTTP2Errors.InvalidStreamIDForPeer() + throw NIOHTTP2Errors.invalidStreamIDForPeer() } self.lastClientStreamID = streamID @@ -246,15 +246,15 @@ struct ConnectionStreamState { /// Adjusts the stream state to reserve a server stream ID. mutating func reserveServerStreamID(_ streamID: HTTP2StreamID) throws { guard self.serverStreamCount < self.maxServerInitiatedStreams else { - throw NIOHTTP2Errors.MaxStreamsViolation() + throw NIOHTTP2Errors.maxStreamsViolation() } guard streamID > self.lastServerStreamID else { - throw NIOHTTP2Errors.StreamIDTooSmall() + throw NIOHTTP2Errors.streamIDTooSmall() } guard streamID.mayBeInitiatedBy(.server) else { - throw NIOHTTP2Errors.InvalidStreamIDForPeer() + throw NIOHTTP2Errors.invalidStreamIDForPeer() } self.lastServerStreamID = streamID @@ -310,13 +310,13 @@ struct ConnectionStreamState { case true where streamID > self.lastClientStreamID, false where streamID > self.lastServerStreamID: // The stream in question is idle. - return .connectionError(underlyingError: NIOHTTP2Errors.NoSuchStream(streamID: streamID), type: .protocolError) + return .connectionError(underlyingError: NIOHTTP2Errors.noSuchStream(streamID: streamID), type: .protocolError) default: // This stream must have already been closed. if ignoreClosed { - return .ignoreFrame + return .ignoreFrame } else { - return .connectionError(underlyingError: NIOHTTP2Errors.NoSuchStream(streamID: streamID), type: .streamClosed) + return .connectionError(underlyingError: NIOHTTP2Errors.noSuchStream(streamID: streamID), type: .streamClosed) } } } diff --git a/Sources/NIOHTTP2/ConnectionStateMachine/FrameReceivingStates/ReceivingGoAwayState.swift b/Sources/NIOHTTP2/ConnectionStateMachine/FrameReceivingStates/ReceivingGoAwayState.swift index 54759deb..ee4db498 100644 --- a/Sources/NIOHTTP2/ConnectionStateMachine/FrameReceivingStates/ReceivingGoAwayState.swift +++ b/Sources/NIOHTTP2/ConnectionStateMachine/FrameReceivingStates/ReceivingGoAwayState.swift @@ -26,7 +26,7 @@ extension ReceivingGoawayState { mutating func receiveGoAwayFrame(lastStreamID: HTTP2StreamID) -> StateMachineResultWithEffect { guard lastStreamID.mayBeInitiatedBy(self.role) || lastStreamID == .rootStream || lastStreamID == .maxID else { // The remote peer has sent a GOAWAY with an invalid stream ID. - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.InvalidStreamIDForPeer(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.invalidStreamIDForPeer(), type: .protocolError), effect: nil) } let droppedStreams = self.streamState.dropAllStreamsWithIDHigherThan(lastStreamID, droppedLocally: false, initiatedBy: self.role) @@ -39,12 +39,12 @@ extension ReceivingGoawayState where Self: RemotelyQuiescingState { mutating func receiveGoAwayFrame(lastStreamID: HTTP2StreamID) -> StateMachineResultWithEffect { guard lastStreamID.mayBeInitiatedBy(self.role) || lastStreamID == .rootStream || lastStreamID == .maxID else { // The remote peer has sent a GOAWAY with an invalid stream ID. - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.InvalidStreamIDForPeer(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.invalidStreamIDForPeer(), type: .protocolError), effect: nil) } if lastStreamID > self.lastLocalStreamID { // The remote peer has attempted to raise the lastStreamID. - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.RaisedGoawayLastStreamID(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.raisedGoawayLastStreamID(), type: .protocolError), effect: nil) } let droppedStreams = self.streamState.dropAllStreamsWithIDHigherThan(lastStreamID, droppedLocally: false, initiatedBy: self.role) diff --git a/Sources/NIOHTTP2/ConnectionStateMachine/FrameReceivingStates/ReceivingPushPromiseState.swift b/Sources/NIOHTTP2/ConnectionStateMachine/FrameReceivingStates/ReceivingPushPromiseState.swift index 8cb5198c..d88e40cf 100644 --- a/Sources/NIOHTTP2/ConnectionStateMachine/FrameReceivingStates/ReceivingPushPromiseState.swift +++ b/Sources/NIOHTTP2/ConnectionStateMachine/FrameReceivingStates/ReceivingPushPromiseState.swift @@ -46,7 +46,7 @@ extension ReceivingPushPromiseState { // // Before any of this, though, we need to check whether the remote peer is even allowed to push! guard self.peerMayPush else { - return StateMachineResultWithEffect(result: .connectionError(underlyingError: NIOHTTP2Errors.PushInViolationOfSetting(), type: .protocolError), effect: nil) + return StateMachineResultWithEffect(result: .connectionError(underlyingError: NIOHTTP2Errors.pushInViolationOfSetting(), type: .protocolError), effect: nil) } let validateHeaderBlock = self.headerBlockValidation == .enabled @@ -75,7 +75,7 @@ extension ReceivingPushPromiseState where Self: LocallyQuiescingState { mutating func receivePushPromise(originalStreamID: HTTP2StreamID, childStreamID: HTTP2StreamID, headers: HPACKHeaders) -> StateMachineResultWithEffect { // This check is duplicated here, because the protocol error of violating this setting is more important than ignoring the frame. guard self.peerMayPush else { - return StateMachineResultWithEffect(result: .connectionError(underlyingError: NIOHTTP2Errors.PushInViolationOfSetting(), type: .protocolError), effect: nil) + return StateMachineResultWithEffect(result: .connectionError(underlyingError: NIOHTTP2Errors.pushInViolationOfSetting(), type: .protocolError), effect: nil) } // If we're a client, the server is forbidden from initiating new streams, as we quiesced. However, RFC 7540 wants us to ignore this. diff --git a/Sources/NIOHTTP2/ConnectionStateMachine/FrameSendingStates/SendingGoawayState.swift b/Sources/NIOHTTP2/ConnectionStateMachine/FrameSendingStates/SendingGoawayState.swift index a1189daf..018080f4 100644 --- a/Sources/NIOHTTP2/ConnectionStateMachine/FrameSendingStates/SendingGoawayState.swift +++ b/Sources/NIOHTTP2/ConnectionStateMachine/FrameSendingStates/SendingGoawayState.swift @@ -26,7 +26,7 @@ extension SendingGoawayState { mutating func sendGoAwayFrame(lastStreamID: HTTP2StreamID) -> StateMachineResultWithEffect { guard lastStreamID.mayBeInitiatedBy(self.peerRole) || lastStreamID == .rootStream || lastStreamID == .maxID else { // The user has sent a GOAWAY with an invalid stream ID. - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.InvalidStreamIDForPeer(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.invalidStreamIDForPeer(), type: .protocolError), effect: nil) } let droppedStreams = self.streamState.dropAllStreamsWithIDHigherThan(lastStreamID, droppedLocally: true, initiatedBy: self.peerRole) @@ -39,12 +39,12 @@ extension SendingGoawayState where Self: LocallyQuiescingState { mutating func sendGoAwayFrame(lastStreamID: HTTP2StreamID) -> StateMachineResultWithEffect { guard lastStreamID.mayBeInitiatedBy(self.peerRole) || lastStreamID == .rootStream || lastStreamID == .maxID else { // The user has sent a GOAWAY with an invalid stream ID. - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.InvalidStreamIDForPeer(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.invalidStreamIDForPeer(), type: .protocolError), effect: nil) } if lastStreamID > self.lastRemoteStreamID { // The user has attempted to raise the lastStreamID. - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.RaisedGoawayLastStreamID(), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.raisedGoawayLastStreamID(), type: .protocolError), effect: nil) } // Ok, this is a valid request, so we can now process it like .active. diff --git a/Sources/NIOHTTP2/ConnectionStateMachine/FrameSendingStates/SendingPushPromiseState.swift b/Sources/NIOHTTP2/ConnectionStateMachine/FrameSendingStates/SendingPushPromiseState.swift index abf8f2ad..e68d0942 100644 --- a/Sources/NIOHTTP2/ConnectionStateMachine/FrameSendingStates/SendingPushPromiseState.swift +++ b/Sources/NIOHTTP2/ConnectionStateMachine/FrameSendingStates/SendingPushPromiseState.swift @@ -45,7 +45,7 @@ extension SendingPushPromiseState { // First, however, we need to check we can push at all! guard self.mayPush else { - return StateMachineResultWithEffect(result: .connectionError(underlyingError: NIOHTTP2Errors.PushInViolationOfSetting(), type: .protocolError), effect: nil) + return StateMachineResultWithEffect(result: .connectionError(underlyingError: NIOHTTP2Errors.pushInViolationOfSetting(), type: .protocolError), effect: nil) } do { diff --git a/Sources/NIOHTTP2/ConnectionStateMachine/HTTP2SettingsState.swift b/Sources/NIOHTTP2/ConnectionStateMachine/HTTP2SettingsState.swift index df63afaf..3700b0b4 100644 --- a/Sources/NIOHTTP2/ConnectionStateMachine/HTTP2SettingsState.swift +++ b/Sources/NIOHTTP2/ConnectionStateMachine/HTTP2SettingsState.swift @@ -91,7 +91,7 @@ struct HTTP2SettingsState { /// - onValueChange: A callback that will be invoked once for each setting change. mutating func receiveSettingsAck(onValueChange: OnValueChangeCallback) throws { guard self.unacknowlegedSettingsFrames.count > 0 else { - throw NIOHTTP2Errors.ReceivedBadSettings() + throw NIOHTTP2Errors.receivedBadSettings() } try self.applySettings(self.unacknowlegedSettingsFrames.removeFirst(), onValueChange: onValueChange) diff --git a/Sources/NIOHTTP2/ContentLengthVerifier.swift b/Sources/NIOHTTP2/ContentLengthVerifier.swift index ebbc0058..e8198205 100644 --- a/Sources/NIOHTTP2/ContentLengthVerifier.swift +++ b/Sources/NIOHTTP2/ContentLengthVerifier.swift @@ -31,7 +31,7 @@ extension ContentLengthVerifier { let newContentLength = expectedContentLength - length if newContentLength < 0 { - throw NIOHTTP2Errors.ContentLengthViolated() + throw NIOHTTP2Errors.contentLengthViolated() } self.expectedContentLength = newContentLength } @@ -42,7 +42,7 @@ extension ContentLengthVerifier { case .none, .some(0): break default: - throw NIOHTTP2Errors.ContentLengthViolated() + throw NIOHTTP2Errors.contentLengthViolated() } } } diff --git a/Sources/NIOHTTP2/DOSHeuristics.swift b/Sources/NIOHTTP2/DOSHeuristics.swift index 95bd62e4..e083444e 100644 --- a/Sources/NIOHTTP2/DOSHeuristics.swift +++ b/Sources/NIOHTTP2/DOSHeuristics.swift @@ -54,7 +54,7 @@ extension DOSHeuristics { } if self.receivedEmptyDataFrames > self.maximumSequentialEmptyDataFrames { - throw NIOHTTP2Errors.ExcessiveEmptyDataFrames() + throw NIOHTTP2Errors.excessiveEmptyDataFrames() } } } diff --git a/Sources/NIOHTTP2/Frame Buffers/ConcurrentStreamBuffer.swift b/Sources/NIOHTTP2/Frame Buffers/ConcurrentStreamBuffer.swift index 35611e77..23b0524b 100644 --- a/Sources/NIOHTTP2/Frame Buffers/ConcurrentStreamBuffer.swift +++ b/Sources/NIOHTTP2/Frame Buffers/ConcurrentStreamBuffer.swift @@ -144,7 +144,7 @@ struct ConcurrentStreamBuffer { // but doesn't match something in the buffer. As a result, it is an error for this frame to have a stream ID lower than or equal to the // highest stream ID in the buffer: if it did, we should have found it when we searched above. If that constraint is breached, fail the write. if let lastElement = self.bufferedFrames.last, frame.streamID <= lastElement.streamID { - throw NIOHTTP2Errors.StreamIDTooSmall() + throw NIOHTTP2Errors.streamIDTooSmall() } // Ok, the stream ID is fine: buffer this frame. @@ -155,7 +155,7 @@ struct ConcurrentStreamBuffer { // This buffer probably has a HEADERS frame in it, and we really don't want to violate the ordering requirements that implies, so we'll buffer this anyway. // We still want StreamIDTooSmall protection here. if frame.streamID <= lastElement.streamID { - throw NIOHTTP2Errors.StreamIDTooSmall() + throw NIOHTTP2Errors.streamIDTooSmall() } // Ok, the stream ID is fine: buffer this frame. @@ -223,9 +223,9 @@ struct ConcurrentStreamBuffer { // If we're currently unbuffering this stream, we need to pass the RST_STREAM frame on for correctness. If we aren't, just // kill it. if writeBuffer.currentlyUnblocking { - return .forwardAndDrop(writeBuffer.frames, NIOHTTP2Errors.StreamClosed(streamID: frame.streamID, errorCode: reason)) + return .forwardAndDrop(writeBuffer.frames, NIOHTTP2Errors.streamClosed(streamID: frame.streamID, errorCode: reason)) } else { - return .succeedAndDrop(writeBuffer.frames, NIOHTTP2Errors.StreamClosed(streamID: frame.streamID, errorCode: reason)) + return .succeedAndDrop(writeBuffer.frames, NIOHTTP2Errors.streamClosed(streamID: frame.streamID, errorCode: reason)) } } diff --git a/Sources/NIOHTTP2/Frame Buffers/ControlFrameBuffer.swift b/Sources/NIOHTTP2/Frame Buffers/ControlFrameBuffer.swift index a7be2405..3308e684 100644 --- a/Sources/NIOHTTP2/Frame Buffers/ControlFrameBuffer.swift +++ b/Sources/NIOHTTP2/Frame Buffers/ControlFrameBuffer.swift @@ -91,7 +91,7 @@ extension ControlFrameBuffer { guard self.pendingControlFrames.count < self.maximumBufferSize else { // Appending another frame would violate the maximum buffer size. We're storing too many frames here, // we gotta move on. - throw NIOHTTP2Errors.ExcessiveOutboundFrameBuffering() + throw NIOHTTP2Errors.excessiveOutboundFrameBuffering() } self.pendingControlFrames.append(PendingControlFrame(frame: frame, promise: promise)) } diff --git a/Sources/NIOHTTP2/Frame Buffers/OutboundFlowControlBuffer.swift b/Sources/NIOHTTP2/Frame Buffers/OutboundFlowControlBuffer.swift index 576b33a0..3cea9962 100644 --- a/Sources/NIOHTTP2/Frame Buffers/OutboundFlowControlBuffer.swift +++ b/Sources/NIOHTTP2/Frame Buffers/OutboundFlowControlBuffer.swift @@ -48,7 +48,7 @@ internal struct OutboundFlowControlBuffer { if !self.streamDataBuffers[frame.streamID].apply({ $0.dataBuffer.bufferWrite((.data(body), promise)) }) { // We don't have this stream ID. This is an internal error, but we won't precondition on it as // it can happen due to channel handler misconfiguration or other weirdness. We'll just complain. - throw NIOHTTP2Errors.NoSuchStream(streamID: frame.streamID) + throw NIOHTTP2Errors.noSuchStream(streamID: frame.streamID) } return .nothing case .headers(let headerContent): @@ -191,7 +191,7 @@ extension OutboundFlowControlBuffer { // RFC 7540 § 5.3, where we can, so this hook is already in place for us to extend later. if streamID == priorityData.dependency { // Streams may not depend on themselves! - throw NIOHTTP2Errors.PriorityCycle(streamID: streamID) + throw NIOHTTP2Errors.priorityCycle(streamID: streamID) } } } diff --git a/Sources/NIOHTTP2/HPACKHeaders+Validation.swift b/Sources/NIOHTTP2/HPACKHeaders+Validation.swift index fae384a7..83aebbaa 100644 --- a/Sources/NIOHTTP2/HPACKHeaders+Validation.swift +++ b/Sources/NIOHTTP2/HPACKHeaders+Validation.swift @@ -58,7 +58,7 @@ fileprivate enum BlockSection { case (.headers, .pseudoHeaderField): // This is an error: it's not allowed to send a pseudo-header field once a regular // header field has been sent. - throw NIOHTTP2Errors.PseudoHeaderAfterRegularHeader(":\(field.baseName)") + throw NIOHTTP2Errors.pseudoHeaderAfterRegularHeader(":\(field.baseName)") } } } @@ -97,7 +97,7 @@ extension HeaderBlockValidator { // and at least the mandatory set. guard validator.allowedPseudoHeaderFields.isSuperset(of: seenPseudoHeaders) && validator.mandatoryPseudoHeaderFields.isSubset(of: seenPseudoHeaders) else { - throw NIOHTTP2Errors.InvalidPseudoHeaders(block) + throw NIOHTTP2Errors.invalidPseudoHeaders(block) } } } @@ -153,7 +153,7 @@ extension RequestBlockValidator: HeaderBlockValidator { case .path: // This is a path pseudo-header. It must not be empty. if value.utf8.count == 0 { - throw NIOHTTP2Errors.EmptyPathHeader() + throw NIOHTTP2Errors.emptyPathHeader() } default: break @@ -163,7 +163,7 @@ extension RequestBlockValidator: HeaderBlockValidator { // We want to check that if the TE header field is present, it only contains "trailers". if name.baseName == "te" && value != "trailers" { - throw NIOHTTP2Errors.ForbiddenHeaderField(name: String(name.baseName), value: value) + throw NIOHTTP2Errors.forbiddenHeaderField(name: String(name.baseName), value: value) } } } @@ -253,7 +253,7 @@ extension HeaderFieldName { } guard baseNameBytes.isValidFieldName else { - throw NIOHTTP2Errors.InvalidHTTP2HeaderFieldName(fieldName) + throw NIOHTTP2Errors.invalidHTTP2HeaderFieldName(fieldName) } } @@ -272,7 +272,7 @@ extension HeaderFieldName { switch self.baseName { case "connection", "transfer-encoding", "proxy-connection": - throw NIOHTTP2Errors.ForbiddenHeaderField(name: String(self.baseName), value: value) + throw NIOHTTP2Errors.forbiddenHeaderField(name: String(self.baseName), value: value) default: return } @@ -382,11 +382,11 @@ extension PseudoHeaders { } guard let pseudoHeaderType = PseudoHeaders(headerFieldName: name) else { - throw NIOHTTP2Errors.UnknownPseudoHeader(":\(name.baseName)") + throw NIOHTTP2Errors.unknownPseudoHeader(":\(name.baseName)") } if self.contains(pseudoHeaderType) { - throw NIOHTTP2Errors.DuplicatePseudoHeader(":\(name.baseName)") + throw NIOHTTP2Errors.duplicatePseudoHeader(":\(name.baseName)") } self.formUnion(pseudoHeaderType) diff --git a/Sources/NIOHTTP2/HTTP2ChannelHandler.swift b/Sources/NIOHTTP2/HTTP2ChannelHandler.swift index c290d7ab..e9a80017 100644 --- a/Sources/NIOHTTP2/HTTP2ChannelHandler.swift +++ b/Sources/NIOHTTP2/HTTP2ChannelHandler.swift @@ -203,13 +203,13 @@ extension NIOHTTP2Handler { do { return try self.frameDecoder.nextFrame() } catch InternalError.codecError(let code) { - self.inboundConnectionErrorTriggered(context: context, underlyingError: NIOHTTP2Errors.UnableToParseFrame(), reason: code) + self.inboundConnectionErrorTriggered(context: context, underlyingError: NIOHTTP2Errors.unableToParseFrame(), reason: code) return nil } catch is NIOHTTP2Errors.BadClientMagic { - self.inboundConnectionErrorTriggered(context: context, underlyingError: NIOHTTP2Errors.BadClientMagic(), reason: .protocolError) + self.inboundConnectionErrorTriggered(context: context, underlyingError: NIOHTTP2Errors.badClientMagic(), reason: .protocolError) return nil } catch is NIOHTTP2Errors.ExcessivelyLargeHeaderBlock { - self.inboundConnectionErrorTriggered(context: context, underlyingError: NIOHTTP2Errors.ExcessivelyLargeHeaderBlock(), reason: .protocolError) + self.inboundConnectionErrorTriggered(context: context, underlyingError: NIOHTTP2Errors.excessivelyLargeHeaderBlock(), reason: .protocolError) return nil } catch { self.inboundConnectionErrorTriggered(context: context, underlyingError: error, reason: .internalError) @@ -470,7 +470,7 @@ extension NIOHTTP2Handler { do { extraFrameData = try self.frameEncoder.encode(frame: frame, to: &self.writeBuffer) } catch InternalError.codecError { - self.outboundErrorTriggered(context: context, promise: promise, underlyingError: NIOHTTP2Errors.UnableToSerializeFrame()) + self.outboundErrorTriggered(context: context, promise: promise, underlyingError: NIOHTTP2Errors.unableToSerializeFrame()) return } catch { self.outboundErrorTriggered(context: context, promise: promise, underlyingError: error) @@ -509,11 +509,8 @@ extension NIOHTTP2Handler { self.inboundEventBuffer.pendingUserEvent(StreamClosedEvent(streamID: streamClosedData.streamID, reason: streamClosedData.reason)) self.inboundEventBuffer.pendingUserEvent(NIOHTTP2WindowUpdatedEvent(streamID: .rootStream, inboundWindowSize: streamClosedData.remoteConnectionWindowSize, outboundWindowSize: streamClosedData.localConnectionWindowSize)) - let failedWrites = self.outboundBuffer.streamClosed(streamClosedData.streamID) - let error = NIOHTTP2Errors.StreamClosed(streamID: streamClosedData.streamID, errorCode: streamClosedData.reason ?? .cancel) - for promise in failedWrites { - promise?.fail(error) - } + let droppedPromises = self.outboundBuffer.streamClosed(streamClosedData.streamID) + self.failDroppedPromises(droppedPromises, streamID: streamClosedData.streamID, errorCode: streamClosedData.reason ?? .cancel) case .streamCreated(let streamCreatedData): self.outboundBuffer.streamCreated(streamCreatedData.streamID, initialWindowSize: streamCreatedData.localStreamWindowSize.map(UInt32.init) ?? 0) self.inboundEventBuffer.pendingUserEvent(NIOHTTP2StreamCreatedEvent(streamID: streamCreatedData.streamID, @@ -523,11 +520,8 @@ extension NIOHTTP2Handler { for droppedStream in streamClosureData.closedStreams { self.inboundEventBuffer.pendingUserEvent(StreamClosedEvent(streamID: droppedStream, reason: .cancel)) - let failedWrites = self.outboundBuffer.streamClosed(droppedStream) - let error = NIOHTTP2Errors.StreamClosed(streamID: droppedStream, errorCode: .cancel) - for promise in failedWrites { - promise?.fail(error) - } + let droppedPromises = self.outboundBuffer.streamClosed(droppedStream) + self.failDroppedPromises(droppedPromises, streamID: droppedStream, errorCode: .cancel) } case .flowControlChange(let change): self.outboundBuffer.connectionWindowSize = change.localConnectionWindowSize @@ -538,11 +532,8 @@ extension NIOHTTP2Handler { } case .streamCreatedAndClosed(let cAndCData): self.outboundBuffer.streamCreated(cAndCData.streamID, initialWindowSize: 0) - let failedWrites = self.outboundBuffer.streamClosed(cAndCData.streamID) - let error = NIOHTTP2Errors.StreamClosed(streamID: cAndCData.streamID, errorCode: .cancel) - for promise in failedWrites { - promise?.fail(error) - } + let droppedPromises = self.outboundBuffer.streamClosed(cAndCData.streamID) + self.failDroppedPromises(droppedPromises, streamID: cAndCData.streamID, errorCode: .cancel) case .remoteSettingsChanged(let settingsChange): if settingsChange.streamWindowSizeChange != 0 { self.outboundBuffer.initialWindowSizeChanged(settingsChange.streamWindowSizeChange) @@ -583,6 +574,23 @@ extension NIOHTTP2Handler { context.flush() } } + + /// Fails any promises in the given collection with a 'StreamClosed' error. + private func failDroppedPromises(_ promises: CompoundOutboundBuffer.DroppedPromisesCollection, + streamID: HTTP2StreamID, + errorCode: HTTP2ErrorCode, + file: String = #file, line: UInt = #line) { + // 'NIOHTTP2Errors.streamClosed' always allocates, if there are no promises then there's no + // need to create the error. + guard promises.contains(where: { $0 != nil }) else { + return + } + + let error = NIOHTTP2Errors.streamClosed(streamID: streamID, errorCode: errorCode, file: file, line: line) + for promise in promises { + promise?.fail(error) + } + } } diff --git a/Sources/NIOHTTP2/HTTP2Error.swift b/Sources/NIOHTTP2/HTTP2Error.swift index 445c424c..bad85cc2 100644 --- a/Sources/NIOHTTP2/HTTP2Error.swift +++ b/Sources/NIOHTTP2/HTTP2Error.swift @@ -17,18 +17,214 @@ public protocol NIOHTTP2Error: Equatable, Error { } /// Errors that NIO raises when handling HTTP/2 connections. public enum NIOHTTP2Errors { + public static func excessiveOutboundFrameBuffering(file: String = #file, line: UInt = #line) -> ExcessiveOutboundFrameBuffering { + return ExcessiveOutboundFrameBuffering(file: file, line: line) + } + + public static func invalidALPNToken(file: String = #file, line: UInt = #line) -> InvalidALPNToken { + return InvalidALPNToken(file: file, line: line) + } + + public static func noSuchStream(streamID: HTTP2StreamID, file: String = #file, line: UInt = #line) -> NoSuchStream { + return NoSuchStream(streamID: streamID, file: file, line: line) + } + + public static func streamClosed(streamID: HTTP2StreamID, errorCode: HTTP2ErrorCode, file: String = #file, line: UInt = #line) -> StreamClosed { + return StreamClosed(streamID: streamID, errorCode: errorCode, file: file, line: line) + } + + public static func badClientMagic(file: String = #file, line: UInt = #line) -> BadClientMagic { + return BadClientMagic(file: file, line: line) + } + + public static func badStreamStateTransition(from state: NIOHTTP2StreamState? = nil, file: String = #file, line: UInt = #line) -> BadStreamStateTransition { + return BadStreamStateTransition(from: state, file: file, line: line) + } + + public static func invalidFlowControlWindowSize(delta: Int, currentWindowSize: Int, file: String = #file, line: UInt = #line) -> InvalidFlowControlWindowSize { + return InvalidFlowControlWindowSize(delta: delta, currentWindowSize: currentWindowSize, file: file, line: line) + } + + public static func flowControlViolation(file: String = #file, line: UInt = #line) -> FlowControlViolation { + return FlowControlViolation(file: file, line: line) + } + + public static func invalidSetting(setting: HTTP2Setting, file: String = #file, line: UInt = #line) -> InvalidSetting { + return InvalidSetting(setting: setting, file: file, line: line) + } + + public static func ioOnClosedConnection(file: String = #file, line: UInt = #line) -> IOOnClosedConnection { + return IOOnClosedConnection(file: file, line: line) + } + + public static func receivedBadSettings(file: String = #file, line: UInt = #line) -> ReceivedBadSettings { + return ReceivedBadSettings(file: file, line: line) + } + + public static func maxStreamsViolation(file: String = #file, line: UInt = #line) -> MaxStreamsViolation { + return MaxStreamsViolation(file: file, line: line) + } + + public static func streamIDTooSmall(file: String = #file, line: UInt = #line) -> StreamIDTooSmall { + return StreamIDTooSmall(file: file, line: line) + } + + public static func missingPreface(file: String = #file, line: UInt = #line) -> MissingPreface { + return MissingPreface(file: file, line: line) + } + + public static func createdStreamAfterGoaway(file: String = #file, line: UInt = #line) -> CreatedStreamAfterGoaway { + return CreatedStreamAfterGoaway(file: file, line: line) + } + + public static func invalidStreamIDForPeer(file: String = #file, line: UInt = #line) -> InvalidStreamIDForPeer { + return InvalidStreamIDForPeer(file: file, line: line) + } + + public static func raisedGoawayLastStreamID(file: String = #file, line: UInt = #line) -> RaisedGoawayLastStreamID { + return RaisedGoawayLastStreamID(file: file, line: line) + } + + public static func invalidWindowIncrementSize(file: String = #file, line: UInt = #line) -> InvalidWindowIncrementSize { + return InvalidWindowIncrementSize(file: file, line: line) + } + + public static func pushInViolationOfSetting(file: String = #file, line: UInt = #line) -> PushInViolationOfSetting { + return PushInViolationOfSetting(file: file, line: line) + } + + public static func unsupported(info: String, file: String = #file, line: UInt = #line) -> Unsupported { + return Unsupported(info: info, file: file, line: line) + } + + public static func unableToSerializeFrame(file: String = #file, line: UInt = #line) -> UnableToSerializeFrame { + return UnableToSerializeFrame(file: file, line: line) + } + + public static func unableToParseFrame(file: String = #file, line: UInt = #line) -> UnableToParseFrame { + return UnableToParseFrame(file: file, line: line) + } + + public static func missingPseudoHeader(_ name: String, file: String = #file, line: UInt = #line) -> MissingPseudoHeader { + return MissingPseudoHeader(name, file: file, line: line) + } + + public static func duplicatePseudoHeader(_ name: String, file: String = #file, line: UInt = #line) -> DuplicatePseudoHeader { + return DuplicatePseudoHeader(name, file: file, line: line) + } + + public static func pseudoHeaderAfterRegularHeader(_ name: String, file: String = #file, line: UInt = #line) -> PseudoHeaderAfterRegularHeader { + return PseudoHeaderAfterRegularHeader(name, file: file, line: line) + } + + public static func unknownPseudoHeader(_ name: String, file: String = #file, line: UInt = #line) -> UnknownPseudoHeader { + return UnknownPseudoHeader(name, file: file, line: line) + } + + public static func invalidPseudoHeaders(_ block: HPACKHeaders, file: String = #file, line: UInt = #line) -> InvalidPseudoHeaders { + return InvalidPseudoHeaders(block, file: file, line: line) + } + + public static func missingHostHeader(file: String = #file, line: UInt = #line) -> MissingHostHeader { + return MissingHostHeader(file: file, line: line) + } + + public static func duplicateHostHeader(file: String = #file, line: UInt = #line) -> DuplicateHostHeader { + return DuplicateHostHeader(file: file, line: line) + } + + public static func emptyPathHeader(file: String = #file, line: UInt = #line) -> EmptyPathHeader { + return EmptyPathHeader(file: file, line: line) + } + + public static func invalidStatusValue(_ value: String, file: String = #file, line: UInt = #line) -> InvalidStatusValue { + return InvalidStatusValue(value, file: file, line: line) + } + + public static func priorityCycle(streamID: HTTP2StreamID, file: String = #file, line: UInt = #line) -> PriorityCycle { + return PriorityCycle(streamID: streamID, file: file, line: line) + } + + public static func trailersWithoutEndStream(streamID: HTTP2StreamID, file: String = #file, line: UInt = #line) -> TrailersWithoutEndStream { + return TrailersWithoutEndStream(streamID: streamID, file: file, line: line) + } + + public static func invalidHTTP2HeaderFieldName(_ fieldName: String, file: String = #file, line: UInt = #line) -> InvalidHTTP2HeaderFieldName { + return InvalidHTTP2HeaderFieldName(fieldName, file: file, line: line) + } + + public static func forbiddenHeaderField(name: String, value: String, file: String = #file, line: UInt = #line) -> ForbiddenHeaderField { + return ForbiddenHeaderField(name: name, value: value, file: file, line: line) + } + + public static func contentLengthViolated(file: String = #file, line: UInt = #line) -> ContentLengthViolated { + return ContentLengthViolated(file: file, line: line) + } + + public static func excessiveEmptyDataFrames(file: String = #file, line: UInt = #line) -> ExcessiveEmptyDataFrames { + return ExcessiveEmptyDataFrames(file: file, line: line) + } + + public static func excessivelyLargeHeaderBlock(file: String = #file, line: UInt = #line) -> ExcessivelyLargeHeaderBlock { + return ExcessivelyLargeHeaderBlock(file: file, line: line) + } + + public static func noStreamIDAvailable(file: String = #file, line: UInt = #line) -> NoStreamIDAvailable { + return NoStreamIDAvailable(file: file, line: line) + } + /// The outbound frame buffers have become filled, and it is not possible to buffer /// further outbound frames. This occurs when the remote peer is generating work /// faster than they are consuming the result. Additional buffering runs the risk of /// memory exhaustion. public struct ExcessiveOutboundFrameBuffering: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "excessiveOutboundFrameBuffering") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: ExcessiveOutboundFrameBuffering, rhs: ExcessiveOutboundFrameBuffering) -> Bool { + return true + } } /// NIO's upgrade handler encountered a successful upgrade to a protocol that it /// does not recognise. public struct InvalidALPNToken: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "invalidALPNToken") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: InvalidALPNToken, rhs: InvalidALPNToken) -> Bool { + return true + } } /// An attempt was made to issue a write on a stream that does not exist. @@ -36,8 +232,21 @@ public enum NIOHTTP2Errors { /// The stream ID that was used that does not exist. public var streamID: HTTP2StreamID + /// The location where the error was thrown. + public let location: String + + @available(*, deprecated, renamed: "noSuchStream") public init(streamID: HTTP2StreamID) { + self.init(streamID: streamID, file: #file, line: #line) + } + + fileprivate init(streamID: HTTP2StreamID, file: String, line: UInt) { self.streamID = streamID + self.location = _location(file: file, line: line) + } + + public static func ==(lhs: NoSuchStream, rhs: NoSuchStream) -> Bool { + return lhs.streamID == rhs.streamID } } @@ -49,53 +258,180 @@ public enum NIOHTTP2Errors { /// The error code associated with the closure. public var errorCode: HTTP2ErrorCode + /// The file and line where the error was created. + public let location: String + + @available(*, deprecated, renamed: "streamClosed") public init(streamID: HTTP2StreamID, errorCode: HTTP2ErrorCode) { + self.init(streamID: streamID, errorCode: errorCode, file: #file, line: #line) + } + + fileprivate init(streamID: HTTP2StreamID, errorCode: HTTP2ErrorCode, file: String, line: UInt) { self.streamID = streamID self.errorCode = errorCode + self.location = _location(file: file, line: line) + } + + public static func ==(lhs: StreamClosed, rhs: StreamClosed) -> Bool { + return lhs.streamID == rhs.streamID && lhs.errorCode == rhs.errorCode } } public struct BadClientMagic: NIOHTTP2Error { - public init() {} + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "badClientMagic") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: BadClientMagic, rhs: BadClientMagic) -> Bool { + return true + } } /// A stream state transition was attempted that was not valid. public struct BadStreamStateTransition: NIOHTTP2Error, CustomStringConvertible { public let fromState: NIOHTTP2StreamState? + /// The location where the error was thrown. + public let location: String + public var description: String { - let stateName = fromState != nil ? "\(fromState!)" : "unknown state" - return "BadStreamStateTransition in state \(stateName)" + let stateName = self.fromState != nil ? "\(self.fromState!)" : "unknown state" + return "BadStreamStateTransition(fromState: \(stateName), location: \(self.location))" } - init(from state: NIOHTTP2StreamState) { - fromState = state + fileprivate init(from state: NIOHTTP2StreamState?, file: String, line: UInt) { + self.fromState = state + self.location = _location(file: file, line: line) } + @available(*, deprecated, renamed: "badStreamStateTransition") public init() { - self.fromState = nil + self.init(from: nil, file: #file, line: #line) + } + + public static func ==(lhs: BadStreamStateTransition, rhs: BadStreamStateTransition) -> Bool { + return lhs.fromState == rhs.fromState } } /// An attempt was made to change the flow control window size, either via /// SETTINGS or WINDOW_UPDATE, but this change would move the flow control /// window size out of bounds. - public struct InvalidFlowControlWindowSize: NIOHTTP2Error { + public struct InvalidFlowControlWindowSize: NIOHTTP2Error, CustomStringConvertible { + private var storage: Storage + + private mutating func copyStorageIfNotUniquelyReferenced() { + if !isKnownUniquelyReferenced(&self.storage) { + self.storage = self.storage.copy() + } + } + + private final class Storage: Equatable { + var delta: Int + var currentWindowSize: Int + var file: String + var line: UInt + + var location: String { + return _location(file: self.file, line: self.line) + } + + init(delta: Int, currentWindowSize: Int, file: String, line: UInt) { + self.delta = delta + self.currentWindowSize = currentWindowSize + self.file = file + self.line = line + } + + func copy() -> Storage { + return Storage(delta: self.delta, currentWindowSize: self.currentWindowSize, file: self.file, line: self.line) + } + + static func ==(lhs: Storage, rhs: Storage) -> Bool { + return lhs.delta == rhs.delta && lhs.currentWindowSize == rhs.currentWindowSize + } + } + /// The delta being applied to the flow control window. - public var delta: Int + public var delta: Int { + get { + return self.storage.delta + } + set { + self.copyStorageIfNotUniquelyReferenced() + self.storage.delta = newValue + } + } /// The size of the flow control window before the delta was applied. - public var currentWindowSize: Int + public var currentWindowSize: Int { + get { + return self.storage.currentWindowSize + } + set { + self.copyStorageIfNotUniquelyReferenced() + self.storage.currentWindowSize = newValue + } + } + + /// The file and line where the error was created. + public var location: String { + get { + return self.storage.location + } + } + + public var description: String { + return "InvalidFlowControlWindowSize(delta: \(self.delta), currentWindowSize: \(self.currentWindowSize), location: \(self.location))" + } + @available(*, deprecated, renamed: "invalidFlowControlWindowSize") public init(delta: Int, currentWindowSize: Int) { - self.delta = delta - self.currentWindowSize = currentWindowSize + self.init(delta: delta, currentWindowSize: currentWindowSize, file: #file, line: #line) + } + + fileprivate init(delta: Int, currentWindowSize: Int, file: String, line: UInt) { + self.storage = Storage(delta: delta, currentWindowSize: currentWindowSize, file: file, line: line) } } /// A frame was sent or received that violates HTTP/2 flow control rules. public struct FlowControlViolation: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "flowControlViolation") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: FlowControlViolation, rhs: FlowControlViolation) -> Bool { + return true + } } /// A SETTINGS frame was sent or received with an invalid setting. @@ -103,112 +439,525 @@ public enum NIOHTTP2Errors { /// The invalid setting. public var setting: HTTP2Setting + /// The location where the error was thrown. + public let location: String + + @available(*, deprecated, renamed: "invalidSetting") public init(setting: HTTP2Setting) { + self.init(setting: setting, file: #file, line: #line) + } + + fileprivate init(setting: HTTP2Setting, file: String, line: UInt) { self.setting = setting + self.location = _location(file: file, line: line) + } + + public static func ==(lhs: InvalidSetting, rhs: InvalidSetting) -> Bool { + return lhs.setting == rhs.setting } } /// An attempt to perform I/O was made on a connection that is already closed. public struct IOOnClosedConnection: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "ioOnClosedConnection") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: IOOnClosedConnection, rhs: IOOnClosedConnection) -> Bool { + return true + } } /// A SETTINGS frame was received that is invalid. public struct ReceivedBadSettings: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "receivedBadSettings") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: ReceivedBadSettings, rhs: ReceivedBadSettings) -> Bool { + return true + } } /// A violation of SETTINGS_MAX_CONCURRENT_STREAMS occurred. public struct MaxStreamsViolation: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "maxStreamsViolation") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: MaxStreamsViolation, rhs: MaxStreamsViolation) -> Bool { + return true + } } /// An attempt was made to use a stream ID that is too small. public struct StreamIDTooSmall: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "streamIDTooSmall") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: StreamIDTooSmall, rhs: StreamIDTooSmall) -> Bool { + return true + } } /// An attempt was made to send a frame without having previously sent a connection preface! public struct MissingPreface: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "missingPreface") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: MissingPreface, rhs: MissingPreface) -> Bool { + return true + } } /// An attempt was made to create a stream after a GOAWAY frame has forbidden further /// stream creation. public struct CreatedStreamAfterGoaway: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "createdStreamAfterGoaway") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: CreatedStreamAfterGoaway, rhs: CreatedStreamAfterGoaway) -> Bool { + return true + } } /// A peer has attempted to create a stream with a stream ID it is not permitted to use. public struct InvalidStreamIDForPeer: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "invalidStreamIDForPeer") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: InvalidStreamIDForPeer, rhs: InvalidStreamIDForPeer) -> Bool { + return true + } } /// An attempt was made to send a new GOAWAY frame whose lastStreamID is higher than the previous value. public struct RaisedGoawayLastStreamID: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "raisedGoawayLastStreamID") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: RaisedGoawayLastStreamID, rhs: RaisedGoawayLastStreamID) -> Bool { + return true + } } /// The size of the window increment is invalid. public struct InvalidWindowIncrementSize: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "invalidWindowIncrementSize") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: InvalidWindowIncrementSize, rhs: InvalidWindowIncrementSize) -> Bool { + return true + } } /// An attempt was made to push a stream, even though the settings forbid it. public struct PushInViolationOfSetting: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "pushInViolationOfSetting") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: PushInViolationOfSetting, rhs: PushInViolationOfSetting) -> Bool { + return true + } } /// An attempt was made to use a currently unsupported feature. - public struct Unsupported: NIOHTTP2Error { - public var info: String - + public struct Unsupported: NIOHTTP2Error, CustomStringConvertible { + private var storage: StringAndLocationStorage + + private mutating func copyStorageIfNotUniquelyReferenced() { + if !isKnownUniquelyReferenced(&self.storage) { + self.storage = self.storage.copy() + } + } + + public var info: String { + get { + return self.storage.value + } + set { + self.copyStorageIfNotUniquelyReferenced() + self.storage.value = newValue + } + } + + /// The file and line where the error was created. + public var location: String { + get { + return self.storage.location + } + } + + public var description: String { + return "Unsupported(info: \(self.info), location: \(self.location))" + } + + @available(*, deprecated, renamed: "unsupported") public init(info: String) { - self.info = info + self.init(info: info, file: #file, line: #line) + } + + fileprivate init(info: String, file: String, line: UInt) { + self.storage = .init(info, file: file, line: line) } } public struct UnableToSerializeFrame: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "unableToSerializeFrame") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: UnableToSerializeFrame, rhs: UnableToSerializeFrame) -> Bool { + return true + } } public struct UnableToParseFrame: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "unableToParseFrame") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: UnableToParseFrame, rhs: UnableToParseFrame) -> Bool { + return true + } } /// A pseudo-header field is missing. - public struct MissingPseudoHeader: NIOHTTP2Error { - public var name: String + public struct MissingPseudoHeader: NIOHTTP2Error, CustomStringConvertible { + private var storage: StringAndLocationStorage + private mutating func copyStorageIfNotUniquelyReferenced() { + if !isKnownUniquelyReferenced(&self.storage) { + self.storage = self.storage.copy() + } + } + + public var name: String { + get { + return self.storage.value + } + set { + self.copyStorageIfNotUniquelyReferenced() + self.storage.value = newValue + } + } + + /// The file and line where the error was created. + public var location: String { + get { + return self.storage.location + } + } + + public var description: String { + return "MissingPseudoHeader(name: \(self.name), location: \(self.location))" + } + + @available(*, deprecated, renamed: "missingPseudoHeader") public init(_ name: String) { - self.name = name + self.init(name, file: #file, line: #line) + } + + fileprivate init(_ name: String, file: String, line: UInt) { + self.storage = .init(name, file: file, line: line) } } /// A pseudo-header field has been duplicated. - public struct DuplicatePseudoHeader: NIOHTTP2Error { - public var name: String + public struct DuplicatePseudoHeader: NIOHTTP2Error, CustomStringConvertible { + private var storage: StringAndLocationStorage + + private mutating func copyStorageIfNotUniquelyReferenced() { + if !isKnownUniquelyReferenced(&self.storage) { + self.storage = self.storage.copy() + } + } + + public var name: String { + get { + return self.storage.value + } + set { + self.copyStorageIfNotUniquelyReferenced() + self.storage.value = newValue + } + } + + /// The file and line where the error was created. + public var location: String { + get { + return self.storage.location + } + } + public var description: String { + return "DuplicatePseudoHeader(name: \(self.name), location: \(self.location))" + } + + @available(*, deprecated, renamed: "duplicatePseudoHeader") public init(_ name: String) { - self.name = name + self.init(name, file: #file, line: #line) + } + + fileprivate init(_ name: String, file: String, line: UInt) { + self.storage = .init(name, file: file, line: line) } } /// A header block contained a pseudo-header after a regular header. - public struct PseudoHeaderAfterRegularHeader: NIOHTTP2Error { - public var name: String + public struct PseudoHeaderAfterRegularHeader: NIOHTTP2Error, CustomStringConvertible { + private var storage: StringAndLocationStorage + + private mutating func copyStorageIfNotUniquelyReferenced() { + if !isKnownUniquelyReferenced(&self.storage) { + self.storage = self.storage.copy() + } + } + + public var name: String { + get { + return self.storage.value + } + set { + self.copyStorageIfNotUniquelyReferenced() + self.storage.value = newValue + } + } + + /// The file and line where the error was created. + public var location: String { + get { + return self.storage.location + } + } + public var description: String { + return "PseudoHeaderAfterRegularHeader(name: \(self.name), location: \(self.location))" + } + + @available(*, deprecated, renamed: "pseudoHeaderAfterRegularHeader") public init(_ name: String) { - self.name = name + self.init(name, file: #file, line: #line) + } + + fileprivate init(_ name: String, file: String, line: UInt) { + self.storage = .init(name, file: file, line: line) } } /// An unknown pseudo-header was received. - public struct UnknownPseudoHeader: NIOHTTP2Error { - public var name: String + public struct UnknownPseudoHeader: NIOHTTP2Error, CustomStringConvertible { + private var storage: StringAndLocationStorage + + private mutating func copyStorageIfNotUniquelyReferenced() { + if !isKnownUniquelyReferenced(&self.storage) { + self.storage = self.storage.copy() + } + } + + public var name: String { + get { + return self.storage.value + } + set { + self.copyStorageIfNotUniquelyReferenced() + self.storage.value = newValue + } + } + + /// The file and line where the error was created. + public var location: String { + get { + return self.storage.location + } + } + + public var description: String { + return "UnknownPseudoHeader(name: \(self.name), location: \(self.location))" + } + @available(*, deprecated, renamed: "unknownPseudoHeader") public init(_ name: String) { - self.name = name + self.init(name, file: #file, line: #line) + } + + fileprivate init(_ name: String, file: String, line: UInt) { + self.storage = .init(name, file: file, line: line) } } @@ -216,32 +965,137 @@ public enum NIOHTTP2Errors { public struct InvalidPseudoHeaders: NIOHTTP2Error { public var headerBlock: HPACKHeaders + /// The location where the error was thrown. + public let location: String + + @available(*, deprecated, renamed: "invalidPseudoHeaders") public init(_ block: HPACKHeaders) { + self.init(block, file: #file, line: #line) + } + + fileprivate init(_ block: HPACKHeaders, file: String, line: UInt) { self.headerBlock = block + self.location = _location(file: file, line: line) + } + + public static func ==(lhs: InvalidPseudoHeaders, rhs: InvalidPseudoHeaders) -> Bool { + return lhs.headerBlock == rhs.headerBlock } } /// An outbound request was about to be sent, but does not contain a Host header. public struct MissingHostHeader: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "missingHostHeader") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: MissingHostHeader, rhs: MissingHostHeader) -> Bool { + return true + } } /// An outbound request was about to be sent, but it contains a duplicated Host header. public struct DuplicateHostHeader: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "duplicateHostHeader") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: DuplicateHostHeader, rhs: DuplicateHostHeader) -> Bool { + return true + } } /// A HTTP/2 header block was received with an empty :path header. public struct EmptyPathHeader: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "emptyPathHeader") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: EmptyPathHeader, rhs: EmptyPathHeader) -> Bool { + return true + } } /// A :status header was received with an invalid value. - public struct InvalidStatusValue: NIOHTTP2Error { - public var value: String + public struct InvalidStatusValue: NIOHTTP2Error, CustomStringConvertible { + private var storage: StringAndLocationStorage + + private mutating func copyStorageIfNotUniquelyReferenced() { + if !isKnownUniquelyReferenced(&self.storage) { + self.storage = self.storage.copy() + } + } + + public var value: String { + get { + return self.storage.value + } + set { + self.copyStorageIfNotUniquelyReferenced() + self.storage.value = newValue + } + } + + /// The file and line where the error was created. + public var location: String { + get { + return self.storage.location + } + } + public var description: String { + return "InvalidStatusValue(value: \(self.value), location: \(self.location))" + } + + @available(*, deprecated, renamed: "invalidStatusValue") public init(_ value: String) { - self.value = value + self.init(value, file: #file, line: #line) + } + + fileprivate init(_ value: String, file: String, line: UInt) { + self.storage = .init(value, file: file, line: line) } } @@ -250,8 +1104,21 @@ public enum NIOHTTP2Errors { /// The affected stream ID. public var streamID: HTTP2StreamID + /// The location where the error was thrown. + public let location: String + + @available(*, deprecated, renamed: "priorityCycle") public init(streamID: HTTP2StreamID) { + self.init(streamID: streamID, file: #file, line: #line) + } + + fileprivate init(streamID: HTTP2StreamID, file: String, line: UInt) { self.streamID = streamID + self.location = _location(file: file, line: line) + } + + public static func ==(lhs: PriorityCycle, rhs: PriorityCycle) -> Bool { + return lhs.streamID == rhs.streamID } } @@ -260,51 +1127,242 @@ public enum NIOHTTP2Errors { /// The affected stream ID. public var streamID: HTTP2StreamID + /// The location where the error was thrown. + public let location: String + + @available(*, deprecated, renamed: "trailersWithoutEndStream") public init(streamID: HTTP2StreamID) { + self.init(streamID: streamID, file: #file, line: #line) + } + + fileprivate init(streamID: HTTP2StreamID, file: String, line: UInt) { self.streamID = streamID + self.location = _location(file: file, line: line) + } + + public static func ==(lhs: TrailersWithoutEndStream, rhs: TrailersWithoutEndStream) -> Bool { + return lhs.streamID == rhs.streamID } } /// An attempt was made to send a header field with a field name that is not valid in HTTP/2. - public struct InvalidHTTP2HeaderFieldName: NIOHTTP2Error { - public var fieldName: String + public struct InvalidHTTP2HeaderFieldName: NIOHTTP2Error, CustomStringConvertible { + private var storage: StringAndLocationStorage + + private mutating func copyStorageIfNotUniquelyReferenced() { + if !isKnownUniquelyReferenced(&self.storage) { + self.storage = self.storage.copy() + } + } - public init(_ fieldName: String) { - self.fieldName = fieldName + public var fieldName: String { + get { + return self.storage.value + } + set { + self.copyStorageIfNotUniquelyReferenced() + self.storage.value = newValue + } + } + + /// The file and line where the error was created. + public var location: String { + get { + return self.storage.location + } + } + + public var description: String { + return "InvalidHTTP2HeaderFieldName(fieldName: \(self.fieldName), location: \(self.location))" + } + + @available(*, deprecated, renamed: "invalidHTTP2HeaderFieldName") + public init(_ name: String) { + self.init(name, file: #file, line: #line) + } + + fileprivate init(_ name: String, file: String, line: UInt) { + self.storage = .init(name, file: file, line: line) } } /// Connection-specific header fields are forbidden in HTTP/2: this error is raised when one is /// sent or received. - public struct ForbiddenHeaderField: NIOHTTP2Error { - public var name: String - public var value: String + public struct ForbiddenHeaderField: NIOHTTP2Error, CustomStringConvertible { + private var storage: Storage + private mutating func copyStorageIfNotUniquelyReferenced() { + if !isKnownUniquelyReferenced(&self.storage) { + self.storage = self.storage.copy() + } + } + + private final class Storage: Equatable { + var name: String + var value: String + var file: String + var line: UInt + + var location: String { + return _location(file: self.file, line: self.line) + } + + init(name: String, value: String, file: String, line: UInt) { + self.name = name + self.value = value + self.file = file + self.line = line + } + + func copy() -> Storage { + return Storage(name: self.name, value: self.value, file: self.file, line: self.line) + } + + static func ==(lhs: Storage, rhs: Storage) -> Bool { + return lhs.name == rhs.name && lhs.value == rhs.value + } + } + + public var name: String { + get { + return self.storage.name + } + set { + self.copyStorageIfNotUniquelyReferenced() + self.storage.name = newValue + } + } + + public var value: String { + get { + return self.storage.value + } + set { + self.copyStorageIfNotUniquelyReferenced() + self.storage.value = newValue + } + } + + /// The file and line where the error was created. + public var location: String { + get { + return self.storage.location + } + } + + public var description: String { + return "ForbiddenHeaderField(name: \(self.name), value: \(self.value), location: \(self.location))" + } + + @available(*, deprecated, renamed: "forbiddenHeaderField") public init(name: String, value: String) { - self.name = name - self.value = value + self.init(name: name, value: value, file: #file, line: #line) + } + + fileprivate init(name: String, value: String, file: String, line: UInt) { + self.storage = Storage(name: name, value: value, file: file, line: line) } } /// A request or response has violated the expected content length, either exceeding or falling beneath it. public struct ContentLengthViolated: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "contentLengthViolated") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: ContentLengthViolated, rhs: ContentLengthViolated) -> Bool { + return true + } } /// The remote peer has sent an excessive number of empty DATA frames, which looks like a denial of service /// attempt, so the connection has been closed. public struct ExcessiveEmptyDataFrames: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "excessiveEmptyDataFrames") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: ExcessiveEmptyDataFrames, rhs: ExcessiveEmptyDataFrames) -> Bool { + return true + } } /// The remote peer has sent a header block so large that NIO refuses to buffer any more data than that. public struct ExcessivelyLargeHeaderBlock: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "excessivelyLargeHeaderBlock") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: ExcessivelyLargeHeaderBlock, rhs: ExcessivelyLargeHeaderBlock) -> Bool { + return true + } } /// The channel does not yet have a stream ID, as it has not reached the network yet. public struct NoStreamIDAvailable: NIOHTTP2Error { - public init() { } + private let file: String + private let line: UInt + + /// The location where the error was thrown. + public var location: String { + return _location(file: self.file, line: self.line) + } + + @available(*, deprecated, renamed: "noStreamIDAvailable") + public init() { + self.init(file: #file, line: #line) + } + + fileprivate init(file: String, line: UInt) { + self.file = file + self.line = line + } + + public static func ==(lhs: NoStreamIDAvailable, rhs: NoStreamIDAvailable) -> Bool { + return true + } } } @@ -319,4 +1377,31 @@ internal enum InternalError: Error { extension InternalError: Hashable { } +private func _location(file: String, line: UInt) -> String { + return "\(file):\(line)" +} + +private final class StringAndLocationStorage: Equatable { + var value: String + var file: String + var line: UInt + + var location: String { + return _location(file: self.file, line: self.line) + } + init(_ value: String, file: String, line: UInt) { + self.value = value + self.file = file + self.line = line + } + + func copy() -> StringAndLocationStorage { + return StringAndLocationStorage(self.value, file: self.file, line: self.line) + } + + static func ==(lhs: StringAndLocationStorage, rhs: StringAndLocationStorage) -> Bool { + // Only compare the value. The 'file' is not relevant here. + return lhs.value == rhs.value + } +} diff --git a/Sources/NIOHTTP2/HTTP2FlowControlWindow.swift b/Sources/NIOHTTP2/HTTP2FlowControlWindow.swift index a84ab794..b65b2b30 100644 --- a/Sources/NIOHTTP2/HTTP2FlowControlWindow.swift +++ b/Sources/NIOHTTP2/HTTP2FlowControlWindow.swift @@ -87,14 +87,14 @@ struct HTTP2FlowControlWindow { assert(amount <= HTTP2FlowControlWindow.maxIncrement) guard amount >= 1 else { - throw NIOHTTP2Errors.InvalidWindowIncrementSize() + throw NIOHTTP2Errors.invalidWindowIncrementSize() } // We now need to bounds check to confirm that our window size will remain in the valid range. We use // subtraction to avoid integer overflow. Note that if the current window size is negative then all window // update increments are valid. guard (self.windowSize < 0) || (HTTP2FlowControlWindow.maxSize - self.windowSize >= amount) else { - throw NIOHTTP2Errors.InvalidFlowControlWindowSize(delta: Int(amount), currentWindowSize: Int(self.windowSize)) + throw NIOHTTP2Errors.invalidFlowControlWindowSize(delta: Int(amount), currentWindowSize: Int(self.windowSize)) } self.windowSize += Int32(amount) @@ -116,7 +116,7 @@ struct HTTP2FlowControlWindow { assert(amount >= -(Int32.max)) guard (self.windowSize < 0) || (HTTP2FlowControlWindow.maxSize - self.windowSize >= amount) else { - throw NIOHTTP2Errors.InvalidFlowControlWindowSize(delta: Int(amount), currentWindowSize: Int(self.windowSize)) + throw NIOHTTP2Errors.invalidFlowControlWindowSize(delta: Int(amount), currentWindowSize: Int(self.windowSize)) } self.windowSize += amount @@ -134,7 +134,7 @@ struct HTTP2FlowControlWindow { let size = Int32(size) guard self.windowSize >= size else { - throw NIOHTTP2Errors.FlowControlViolation() + throw NIOHTTP2Errors.flowControlViolation() } self.windowSize -= size diff --git a/Sources/NIOHTTP2/HTTP2FrameParser.swift b/Sources/NIOHTTP2/HTTP2FrameParser.swift index e99f950b..b0c56979 100644 --- a/Sources/NIOHTTP2/HTTP2FrameParser.swift +++ b/Sources/NIOHTTP2/HTTP2FrameParser.swift @@ -326,7 +326,7 @@ struct HTTP2FrameDecoder { } guard clientMagic == HTTP2FrameDecoder.clientMagicBytes else { - throw NIOHTTP2Errors.BadClientMagic() + throw NIOHTTP2Errors.badClientMagic() } self.state = .accumulatingFrameHeader(.init(unusedBytes: state.pendingBytes)) @@ -349,7 +349,7 @@ struct HTTP2FrameDecoder { // Not a DATA frame. Before we move on, do a quick preflight: if this frame header is for a frame that will // definitely violate SETTINGS_MAX_HEADER_LIST_SIZE, quit now. if header.type == 1 && header.length > self.headerDecoder.maxHeaderListSize { - throw NIOHTTP2Errors.ExcessivelyLargeHeaderBlock() + throw NIOHTTP2Errors.excessivelyLargeHeaderBlock() } self.state = .accumulatingData(AccumulatingPayloadParserState(fromIdle: state, header: header)) @@ -572,7 +572,7 @@ struct HTTP2FrameDecoder { // Check whether there is any possibility of this payload decompressing and fitting in max header list size. // If there isn't, kill it. guard state.accumulatedPayload.readableBytes + header.length <= self.headerDecoder.maxHeaderListSize else { - throw NIOHTTP2Errors.ExcessivelyLargeHeaderBlock() + throw NIOHTTP2Errors.excessivelyLargeHeaderBlock() } self.state = .accumulatingContinuationPayload(AccumulatingContinuationPayloadParserState(fromAccumulatingHeaderBlockFragments: state, continuationHeader: header)) @@ -1031,7 +1031,7 @@ struct HTTP2FrameEncoder { case .data(let dataContent): if dataContent.paddingBytes != nil { // we don't support sending padded frames just now - throw NIOHTTP2Errors.Unsupported(info: "Padding is not supported on sent frames at this time") + throw NIOHTTP2Errors.unsupported(info: "Padding is not supported on sent frames at this time") } if dataContent.endStream { @@ -1043,7 +1043,7 @@ struct HTTP2FrameEncoder { case .headers(let headerData): if headerData.paddingBytes != nil { // we don't support sending padded frames just now - throw NIOHTTP2Errors.Unsupported(info: "Padding is not supported on sent frames at this time") + throw NIOHTTP2Errors.unsupported(info: "Padding is not supported on sent frames at this time") } flags.insert(.endHeaders) @@ -1099,7 +1099,7 @@ struct HTTP2FrameEncoder { case .pushPromise(let pushPromiseData): if pushPromiseData.paddingBytes != nil { // we don't support sending padded frames just now - throw NIOHTTP2Errors.Unsupported(info: "Padding is not supported on sent frames at this time") + throw NIOHTTP2Errors.unsupported(info: "Padding is not supported on sent frames at this time") } let streamVal: UInt32 = UInt32(pushPromiseData.pushedStreamID) diff --git a/Sources/NIOHTTP2/HTTP2PipelineHelpers.swift b/Sources/NIOHTTP2/HTTP2PipelineHelpers.swift index a1036b0d..4ddbbc5f 100644 --- a/Sources/NIOHTTP2/HTTP2PipelineHelpers.swift +++ b/Sources/NIOHTTP2/HTTP2PipelineHelpers.swift @@ -198,7 +198,7 @@ extension Channel { case .negotiated: // We negotiated something that isn't HTTP/1.1. This is a bad scene, and is a good indication // of a user configuration error. We're going to close the connection directly. - return self.close().flatMap { self.eventLoop.makeFailedFuture(NIOHTTP2Errors.InvalidALPNToken()) } + return self.close().flatMap { self.eventLoop.makeFailedFuture(NIOHTTP2Errors.invalidALPNToken()) } } } diff --git a/Sources/NIOHTTP2/HTTP2StreamChannel.swift b/Sources/NIOHTTP2/HTTP2StreamChannel.swift index 735774e6..132b0bd1 100644 --- a/Sources/NIOHTTP2/HTTP2StreamChannel.swift +++ b/Sources/NIOHTTP2/HTTP2StreamChannel.swift @@ -362,7 +362,7 @@ final class HTTP2StreamChannel: Channel, ChannelCore { if let streamID = self.streamID { return streamID as! Option.Value } else { - throw NIOHTTP2Errors.NoStreamIDAvailable() + throw NIOHTTP2Errors.noStreamIDAvailable() } case _ as ChannelOptions.Types.AutoReadOption: return self.autoRead as! Option.Value @@ -785,7 +785,7 @@ internal extension HTTP2StreamChannel { if let reason = reason { // To receive from the network, it must be safe to force-unwrap here. - let err = NIOHTTP2Errors.StreamClosed(streamID: self.streamID!, errorCode: reason) + let err = NIOHTTP2Errors.streamClosed(streamID: self.streamID!, errorCode: reason) self.errorEncountered(error: err) } else { self.closedCleanly() diff --git a/Sources/NIOHTTP2/HTTP2StreamMultiplexer.swift b/Sources/NIOHTTP2/HTTP2StreamMultiplexer.swift index fcac381a..16270807 100644 --- a/Sources/NIOHTTP2/HTTP2StreamMultiplexer.swift +++ b/Sources/NIOHTTP2/HTTP2StreamMultiplexer.swift @@ -99,7 +99,7 @@ public final class HTTP2StreamMultiplexer: ChannelInboundHandler, ChannelOutboun } else { // This frame is for a stream we know nothing about. We can't do much about it, so we // are going to fire an error and drop the frame. - let error = NIOHTTP2Errors.NoSuchStream(streamID: streamID) + let error = NIOHTTP2Errors.noSuchStream(streamID: streamID) context.fireErrorCaught(error) } } diff --git a/Sources/NIOHTTP2/HTTP2ToHTTP1Codec.swift b/Sources/NIOHTTP2/HTTP2ToHTTP1Codec.swift index 6271ecec..0af533e1 100644 --- a/Sources/NIOHTTP2/HTTP2ToHTTP1Codec.swift +++ b/Sources/NIOHTTP2/HTTP2ToHTTP1Codec.swift @@ -600,7 +600,7 @@ internal extension HTTPResponseHead { // A response head should have only one psuedo-header. We strip it off. let statusHeader = try headers.peekPseudoHeader(name: ":status") guard let integerStatus = Int(statusHeader, radix: 10) else { - throw NIOHTTP2Errors.InvalidStatusValue(statusHeader) + throw NIOHTTP2Errors.invalidStatusValue(statusHeader) } let status = HTTPResponseStatus(statusCode: integerStatus) self.init(version: .init(major: 2, minor: 0), status: status, headers: HTTPHeaders(regularHeadersFrom: headers)) @@ -622,7 +622,7 @@ extension HPACKHeaders { for (fieldName, fieldValue, _) in self { if name == fieldName { guard headerValue == nil else { - throw NIOHTTP2Errors.DuplicatePseudoHeader(name) + throw NIOHTTP2Errors.duplicatePseudoHeader(name) } headerValue = fieldValue } @@ -631,7 +631,7 @@ extension HPACKHeaders { if let headerValue = headerValue { return headerValue } else { - throw NIOHTTP2Errors.MissingPseudoHeader(name) + throw NIOHTTP2Errors.missingPseudoHeader(name) } } } @@ -660,7 +660,7 @@ extension HTTPHeaders { for header in requestHead.headers { if header.name.lowercased() == "host" { if authorityHeader != nil { - throw NIOHTTP2Errors.DuplicateHostHeader() + throw NIOHTTP2Errors.duplicateHostHeader() } authorityHeader = header.value @@ -671,7 +671,7 @@ extension HTTPHeaders { // Now we go back and fill in the authority header. guard let actualAuthorityHeader = authorityHeader else { - throw NIOHTTP2Errors.MissingHostHeader() + throw NIOHTTP2Errors.missingHostHeader() } newHeaders[3].1 = actualAuthorityHeader diff --git a/Sources/NIOHTTP2/StreamStateMachine.swift b/Sources/NIOHTTP2/StreamStateMachine.swift index 406d83a1..c0bebd44 100644 --- a/Sources/NIOHTTP2/StreamStateMachine.swift +++ b/Sources/NIOHTTP2/StreamStateMachine.swift @@ -383,9 +383,9 @@ extension HTTP2StreamStateMachine { // seems reasonable to me: specifically, if we have a stream to fail, fail it, otherwise treat // the error as connection scoped.) case .idle(.server, _, _), .closed: - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.BadStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.badStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .protocolError), effect: nil) case .reservedRemote, .halfClosedLocalPeerIdle, .halfClosedLocalPeerActive: - return .init(result: .streamError(streamID: self.streamID, underlyingError: NIOHTTP2Errors.BadStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .protocolError), effect: nil) + return .init(result: .streamError(streamID: self.streamID, underlyingError: NIOHTTP2Errors.badStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .protocolError), effect: nil) } } catch let error where error is NIOHTTP2Errors.ContentLengthViolated { return .init(result: .streamError(streamID: self.streamID, underlyingError: error, type: .protocolError), effect: nil) @@ -514,9 +514,9 @@ extension HTTP2StreamStateMachine { // seems reasonable to me: specifically, if we have a stream to fail, fail it, otherwise treat // the error as connection scoped.) case .idle(.client, _, _), .closed: - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.BadStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.badStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .protocolError), effect: nil) case .reservedLocal, .halfClosedRemoteLocalIdle, .halfClosedRemoteLocalActive: - return .init(result: .streamError(streamID: self.streamID, underlyingError: NIOHTTP2Errors.BadStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .protocolError), effect: nil) + return .init(result: .streamError(streamID: self.streamID, underlyingError: NIOHTTP2Errors.badStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .protocolError), effect: nil) } } catch let error where error is NIOHTTP2Errors.ContentLengthViolated { return .init(result: .streamError(streamID: self.streamID, underlyingError: error, type: .protocolError), effect: nil) @@ -586,7 +586,7 @@ extension HTTP2StreamStateMachine { // Sending a DATA frame outside any of these states is a stream error of type STREAM_CLOSED (RFC7540 § 6.1) case .idle, .halfOpenRemoteLocalIdle, .reservedLocal, .reservedRemote, .halfClosedLocalPeerIdle, .halfClosedLocalPeerActive, .halfClosedRemoteLocalIdle, .closed: - return .init(result: .streamError(streamID: self.streamID, underlyingError: NIOHTTP2Errors.BadStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .streamClosed), effect: nil) + return .init(result: .streamError(streamID: self.streamID, underlyingError: NIOHTTP2Errors.badStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .streamClosed), effect: nil) } } catch let error where error is NIOHTTP2Errors.FlowControlViolation { return .init(result: .streamError(streamID: self.streamID, underlyingError: error, type: .flowControlError), effect: nil) @@ -657,7 +657,7 @@ extension HTTP2StreamStateMachine { // Receiving a DATA frame outside any of these states is a stream error of type STREAM_CLOSED (RFC7540 § 6.1) case .idle, .halfOpenLocalPeerIdle, .reservedLocal, .reservedRemote, .halfClosedLocalPeerIdle, .halfClosedRemoteLocalActive, .halfClosedRemoteLocalIdle, .closed: - return .init(result: .streamError(streamID: self.streamID, underlyingError: NIOHTTP2Errors.BadStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .streamClosed), effect: nil) + return .init(result: .streamError(streamID: self.streamID, underlyingError: NIOHTTP2Errors.badStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .streamClosed), effect: nil) } } catch let error where error is NIOHTTP2Errors.FlowControlViolation { return .init(result: .streamError(streamID: self.streamID, underlyingError: error, type: .flowControlError), effect: nil) @@ -693,7 +693,7 @@ extension HTTP2StreamStateMachine { .fullyOpen(localRole: .client, localContentLength: _, remoteContentLength: _, localWindow: _, remoteWindow: _), .halfClosedRemoteLocalActive(localRole: .client, initiatedBy: _, localContentLength: _, localWindow: _), .halfClosedRemoteLocalActive(localRole: .server, initiatedBy: .server, localContentLength: _, localWindow: _): - return .init(result: .streamError(streamID: self.streamID, underlyingError: NIOHTTP2Errors.BadStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .protocolError), effect: nil) + return .init(result: .streamError(streamID: self.streamID, underlyingError: NIOHTTP2Errors.badStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .protocolError), effect: nil) } } @@ -720,7 +720,7 @@ extension HTTP2StreamStateMachine { .fullyOpen(localRole: .server, localContentLength: _, remoteContentLength: _, localWindow: _, remoteWindow: _), .halfClosedLocalPeerActive(localRole: .server, initiatedBy: _, remoteContentLength: _, remoteWindow: _), .halfClosedLocalPeerActive(localRole: .client, initiatedBy: .server, remoteContentLength: _, remoteWindow: _): - return .init(result: .streamError(streamID: self.streamID, underlyingError: NIOHTTP2Errors.BadStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .protocolError), effect: nil) + return .init(result: .streamError(streamID: self.streamID, underlyingError: NIOHTTP2Errors.badStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .protocolError), effect: nil) } } @@ -769,7 +769,7 @@ extension HTTP2StreamStateMachine { windowEffect = .windowSizeChange(.init(streamID: self.streamID, localStreamWindowSize: nil, remoteStreamWindowSize: Int(remoteWindow))) case .idle, .reservedLocal, .halfClosedRemoteLocalIdle, .halfClosedRemoteLocalActive, .closed: - return .init(result: .streamError(streamID: self.streamID, underlyingError: NIOHTTP2Errors.BadStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .protocolError), effect: nil) + return .init(result: .streamError(streamID: self.streamID, underlyingError: NIOHTTP2Errors.badStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .protocolError), effect: nil) } } catch let error where error is NIOHTTP2Errors.InvalidFlowControlWindowSize { return .init(result: .streamError(streamID: self.streamID, underlyingError: error, type: .flowControlError), effect: nil) @@ -833,7 +833,7 @@ extension HTTP2StreamStateMachine { windowEffect = nil case .idle, .reservedRemote, .closed: - return .init(result: .streamError(streamID: self.streamID, underlyingError: NIOHTTP2Errors.BadStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .protocolError), effect: nil) + return .init(result: .streamError(streamID: self.streamID, underlyingError: NIOHTTP2Errors.badStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .protocolError), effect: nil) } } catch let error where error is NIOHTTP2Errors.InvalidFlowControlWindowSize { return .init(result: .streamError(streamID: self.streamID, underlyingError: error, type: .flowControlError), effect: nil) @@ -856,7 +856,7 @@ extension HTTP2StreamStateMachine { mutating func receiveRstStream(reason: HTTP2ErrorCode) -> StateMachineResultWithStreamEffect { // We can receive RST_STREAM frames in any state but idle. if case .idle = self.state { - return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.BadStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .protocolError), effect: nil) + return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.badStreamStateTransition(from: NIOHTTP2StreamState.get(self.state)), type: .protocolError), effect: nil) } self.state = .closed(reason: reason) @@ -1004,7 +1004,7 @@ extension HTTP2StreamStateMachine { // End stream must be set on trailers. guard endStream else { - return StateMachineResultWithStreamEffect(result: .streamError(streamID: self.streamID, underlyingError: NIOHTTP2Errors.TrailersWithoutEndStream(streamID: self.streamID), type: .protocolError), effect: nil) + return StateMachineResultWithStreamEffect(result: .streamError(streamID: self.streamID, underlyingError: NIOHTTP2Errors.trailersWithoutEndStream(streamID: self.streamID), type: .protocolError), effect: nil) } self.state = target diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index d1f40eea..d9faeb07 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -44,6 +44,7 @@ class LinuxMainRunnerImpl: LinuxMainRunner { testCase(HPACKCodingTests.allTests), testCase(HPACKIntegrationTests.allTests), testCase(HPACKRegressionTests.allTests), + testCase(HTTP2ErrorTests.allTests), testCase(HTTP2FrameParserTests.allTests), testCase(HTTP2FramePayloadStreamMultiplexerTests.allTests), testCase(HTTP2FramePayloadToHTTP1CodecTests.allTests), diff --git a/Tests/NIOHTTP2Tests/CompoundOutboundBufferTest.swift b/Tests/NIOHTTP2Tests/CompoundOutboundBufferTest.swift index 80456526..cb464bd7 100644 --- a/Tests/NIOHTTP2Tests/CompoundOutboundBufferTest.swift +++ b/Tests/NIOHTTP2Tests/CompoundOutboundBufferTest.swift @@ -149,7 +149,7 @@ final class CompoundOutboundBufferTest: XCTestCase { // Ok, now we complete stream 1. This makes the next frame elegible for emission. XCTAssertEqual(buffer.streamClosed(1).count, 0) - buffer.nextFlushedWritableFrame(channelWritable: true).assertError(NIOHTTP2Errors.NoSuchStream(streamID: 3)) + buffer.nextFlushedWritableFrame(channelWritable: true).assertError(NIOHTTP2Errors.noSuchStream(streamID: 3)) } func testBufferedFrameDrops() { @@ -181,7 +181,7 @@ final class CompoundOutboundBufferTest: XCTestCase { future.map { results[idx] = true }.whenFailure { error in - XCTAssertEqual(error as? NIOHTTP2Errors.StreamClosed, NIOHTTP2Errors.StreamClosed(streamID: 3, errorCode: .protocolError)) + XCTAssertEqual(error as? NIOHTTP2Errors.StreamClosed, NIOHTTP2Errors.streamClosed(streamID: 3, errorCode: .protocolError)) results[idx] = false } } @@ -192,13 +192,13 @@ final class CompoundOutboundBufferTest: XCTestCase { // Now, fail stream one. for promise in buffer.streamClosed(1) { - promise?.fail(NIOHTTP2Errors.StreamClosed(streamID: 3, errorCode: .protocolError)) + promise?.fail(NIOHTTP2Errors.streamClosed(streamID: 3, errorCode: .protocolError)) } XCTAssertEqual(results, [true, false, nil, nil]) // Now fail stream three. for promise in buffer.streamClosed(3) { - promise?.fail(NIOHTTP2Errors.StreamClosed(streamID: 3, errorCode: .protocolError)) + promise?.fail(NIOHTTP2Errors.streamClosed(streamID: 3, errorCode: .protocolError)) } XCTAssertEqual(results, [true, false, false, false]) } @@ -207,10 +207,10 @@ final class CompoundOutboundBufferTest: XCTestCase { var buffer = CompoundOutboundBuffer(mode: .client, initialMaxOutboundStreams: 1, maxBufferedControlFrames: 1000) XCTAssertThrowsError(try buffer.priorityUpdate(streamID: 1, priorityData: .init(exclusive: false, dependency: 1, weight: 36))) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.PriorityCycle, NIOHTTP2Errors.PriorityCycle(streamID: 1)) + XCTAssertEqual(error as? NIOHTTP2Errors.PriorityCycle, NIOHTTP2Errors.priorityCycle(streamID: 1)) } XCTAssertThrowsError(try buffer.priorityUpdate(streamID: 1, priorityData: .init(exclusive: true, dependency: 1, weight: 36))) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.PriorityCycle, NIOHTTP2Errors.PriorityCycle(streamID: 1)) + XCTAssertEqual(error as? NIOHTTP2Errors.PriorityCycle, NIOHTTP2Errors.priorityCycle(streamID: 1)) } } diff --git a/Tests/NIOHTTP2Tests/ConcurrentStreamBufferTest.swift b/Tests/NIOHTTP2Tests/ConcurrentStreamBufferTest.swift index 1cd61d25..15f86077 100644 --- a/Tests/NIOHTTP2Tests/ConcurrentStreamBufferTest.swift +++ b/Tests/NIOHTTP2Tests/ConcurrentStreamBufferTest.swift @@ -253,7 +253,7 @@ final class ConcurrentStreamBufferTests: XCTestCase { promise.map { writeStatus[idx] = true }.whenFailure { error in - XCTAssertEqual(error as? NIOHTTP2Errors.StreamClosed, NIOHTTP2Errors.StreamClosed(streamID: 3, errorCode: .cancel)) + XCTAssertEqual(error as? NIOHTTP2Errors.StreamClosed, NIOHTTP2Errors.streamClosed(streamID: 3, errorCode: .cancel)) writeStatus[idx] = false } } @@ -284,7 +284,7 @@ final class ConcurrentStreamBufferTests: XCTestCase { write.1?.fail(error) } - XCTAssertEqual(error, NIOHTTP2Errors.StreamClosed(streamID: 3, errorCode: .cancel)) + XCTAssertEqual(error, NIOHTTP2Errors.streamClosed(streamID: 3, errorCode: .cancel)) XCTAssertEqual(writeStatus, Array(repeating: true as Bool?, count: 15) + Array(repeating: false as Bool?, count: 15)) } @@ -309,7 +309,7 @@ final class ConcurrentStreamBufferTests: XCTestCase { promise.map { writeStatus[idx] = true }.whenFailure { error in - XCTAssertEqual(error as? NIOHTTP2Errors.StreamClosed, NIOHTTP2Errors.StreamClosed(streamID: 3, errorCode: .cancel)) + XCTAssertEqual(error as? NIOHTTP2Errors.StreamClosed, NIOHTTP2Errors.streamClosed(streamID: 3, errorCode: .cancel)) writeStatus[idx] = false } } @@ -416,7 +416,7 @@ final class ConcurrentStreamBufferTests: XCTestCase { promise.map { writeStatus[idx] = true }.whenFailure { error in - XCTAssertEqual(error as? NIOHTTP2Errors.StreamClosed, NIOHTTP2Errors.StreamClosed(streamID: 3, errorCode: .protocolError)) + XCTAssertEqual(error as? NIOHTTP2Errors.StreamClosed, NIOHTTP2Errors.streamClosed(streamID: 3, errorCode: .protocolError)) writeStatus[idx] = false } } @@ -435,7 +435,7 @@ final class ConcurrentStreamBufferTests: XCTestCase { return } for (_, promise) in droppedFrames { - promise?.fail(NIOHTTP2Errors.StreamClosed(streamID: 3, errorCode: .protocolError)) + promise?.fail(NIOHTTP2Errors.streamClosed(streamID: 3, errorCode: .protocolError)) } XCTAssertEqual(writeStatus, Array(repeating: false, count: 15)) diff --git a/Tests/NIOHTTP2Tests/ConnectionStateMachineTests.swift b/Tests/NIOHTTP2Tests/ConnectionStateMachineTests.swift index ae70a2a0..e6473c80 100644 --- a/Tests/NIOHTTP2Tests/ConnectionStateMachineTests.swift +++ b/Tests/NIOHTTP2Tests/ConnectionStateMachineTests.swift @@ -264,7 +264,7 @@ class ConnectionStateMachineTests: XCTestCase { self.server = savedServerState // Test that BadStreamStateTransition conforms to CustomStringConvertible - XCTAssertEqual(lastBadStreamStateTransition?.description, "BadStreamStateTransition in state halfClosedLocalPeerActive") + XCTAssertTrue(lastBadStreamStateTransition!.description.starts(with: "BadStreamStateTransition(fromState: halfClosedLocalPeerActive")) } func testOpeningConnectionWhileServerPreambleMissing() { diff --git a/Tests/NIOHTTP2Tests/ControlFrameBufferTests.swift b/Tests/NIOHTTP2Tests/ControlFrameBufferTests.swift index f39158bd..ec1acfd9 100644 --- a/Tests/NIOHTTP2Tests/ControlFrameBufferTests.swift +++ b/Tests/NIOHTTP2Tests/ControlFrameBufferTests.swift @@ -101,7 +101,7 @@ final class ControlFrameBufferTests: XCTestCase { XCTAssertNoThrow(try buffer.processOutboundFrame(.headers, promise: nil, channelWritable: false).assertNothing()) } XCTAssertThrowsError(try buffer.processOutboundFrame(.headers, promise: nil, channelWritable: false)) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.ExcessiveOutboundFrameBuffering, NIOHTTP2Errors.ExcessiveOutboundFrameBuffering()) + XCTAssertEqual(error as? NIOHTTP2Errors.ExcessiveOutboundFrameBuffering, NIOHTTP2Errors.excessiveOutboundFrameBuffering()) } } } diff --git a/Tests/NIOHTTP2Tests/HTTP2ErrorTests+XCTest.swift b/Tests/NIOHTTP2Tests/HTTP2ErrorTests+XCTest.swift new file mode 100644 index 00000000..10a095ad --- /dev/null +++ b/Tests/NIOHTTP2Tests/HTTP2ErrorTests+XCTest.swift @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftNIO open source project +// +// Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of SwiftNIO project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// +// +// HTTP2ErrorTests+XCTest.swift +// +import XCTest + +/// +/// NOTE: This file was generated by generate_linux_tests.rb +/// +/// Do NOT edit this file directly as it will be regenerated automatically when needed. +/// + +extension HTTP2ErrorTests { + + @available(*, deprecated, message: "not actually deprecated. Just deprecated to allow deprecated tests (which test deprecated functionality) without warnings") + static var allTests : [(String, (HTTP2ErrorTests) -> () throws -> Void)] { + return [ + ("testEquatableExcludesFileAndLine", testEquatableExcludesFileAndLine), + ("testFitsInAnExistentialContainer", testFitsInAnExistentialContainer), + ] + } +} + diff --git a/Tests/NIOHTTP2Tests/HTTP2ErrorTests.swift b/Tests/NIOHTTP2Tests/HTTP2ErrorTests.swift new file mode 100644 index 00000000..b0b79e79 --- /dev/null +++ b/Tests/NIOHTTP2Tests/HTTP2ErrorTests.swift @@ -0,0 +1,236 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftNIO open source project +// +// Copyright (c) 2020 Apple Inc. and the SwiftNIO project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of SwiftNIO project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +import XCTest +import NIOHTTP2 + +class HTTP2ErrorTests: XCTestCase { + func testEquatableExcludesFileAndLine() throws { + XCTAssertEqual(NIOHTTP2Errors.excessiveOutboundFrameBuffering(), + NIOHTTP2Errors.excessiveOutboundFrameBuffering(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.invalidALPNToken(), + NIOHTTP2Errors.invalidALPNToken(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.noSuchStream(streamID: .rootStream), + NIOHTTP2Errors.noSuchStream(streamID: .rootStream, file: "", line: 0)) + + XCTAssertNotEqual(NIOHTTP2Errors.noSuchStream(streamID: 1), + NIOHTTP2Errors.noSuchStream(streamID: 2)) + + XCTAssertEqual(NIOHTTP2Errors.streamClosed(streamID: .rootStream, errorCode: .cancel), + NIOHTTP2Errors.streamClosed(streamID: .rootStream, errorCode: .cancel, file: "", line: 0)) + + XCTAssertNotEqual(NIOHTTP2Errors.streamClosed(streamID: 1, errorCode: .cancel), + NIOHTTP2Errors.streamClosed(streamID: 1, errorCode: .compressionError)) + + XCTAssertNotEqual(NIOHTTP2Errors.streamClosed(streamID: 1, errorCode: .cancel), + NIOHTTP2Errors.streamClosed(streamID: 2, errorCode: .cancel)) + + XCTAssertEqual(NIOHTTP2Errors.badClientMagic(), + NIOHTTP2Errors.badClientMagic(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.badStreamStateTransition(), + NIOHTTP2Errors.badStreamStateTransition(file: "", line: 0)) + + XCTAssertNotEqual(NIOHTTP2Errors.badStreamStateTransition(from: .closed), + NIOHTTP2Errors.badStreamStateTransition()) + + XCTAssertEqual(NIOHTTP2Errors.invalidFlowControlWindowSize(delta: 1, currentWindowSize: 2), + NIOHTTP2Errors.invalidFlowControlWindowSize(delta: 1, currentWindowSize: 2, file: "", line: 0)) + + XCTAssertNotEqual(NIOHTTP2Errors.invalidFlowControlWindowSize(delta: 1, currentWindowSize: 2), + NIOHTTP2Errors.invalidFlowControlWindowSize(delta: 2, currentWindowSize: 2)) + + XCTAssertNotEqual(NIOHTTP2Errors.invalidFlowControlWindowSize(delta: 1, currentWindowSize: 3), + NIOHTTP2Errors.invalidFlowControlWindowSize(delta: 1, currentWindowSize: 2)) + + XCTAssertEqual(NIOHTTP2Errors.flowControlViolation(), + NIOHTTP2Errors.flowControlViolation(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.invalidSetting(setting: .init(parameter: .maxConcurrentStreams, value: 1)), + NIOHTTP2Errors.invalidSetting(setting: .init(parameter: .maxConcurrentStreams, value: 1), file: "", line: 0)) + + XCTAssertNotEqual(NIOHTTP2Errors.invalidSetting(setting: .init(parameter: .maxConcurrentStreams, value: 1)), + NIOHTTP2Errors.invalidSetting(setting: .init(parameter: .maxConcurrentStreams, value: 2))) + + XCTAssertEqual(NIOHTTP2Errors.ioOnClosedConnection(), + NIOHTTP2Errors.ioOnClosedConnection(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.receivedBadSettings(), + NIOHTTP2Errors.receivedBadSettings(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.maxStreamsViolation(), + NIOHTTP2Errors.maxStreamsViolation(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.streamIDTooSmall(), + NIOHTTP2Errors.streamIDTooSmall(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.missingPreface(), + NIOHTTP2Errors.missingPreface(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.createdStreamAfterGoaway(), + NIOHTTP2Errors.createdStreamAfterGoaway(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.invalidStreamIDForPeer(), + NIOHTTP2Errors.invalidStreamIDForPeer(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.raisedGoawayLastStreamID(), + NIOHTTP2Errors.raisedGoawayLastStreamID(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.invalidWindowIncrementSize(), + NIOHTTP2Errors.invalidWindowIncrementSize(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.pushInViolationOfSetting(), + NIOHTTP2Errors.pushInViolationOfSetting(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.unsupported(info: "info"), + NIOHTTP2Errors.unsupported(info: "info", file: "", line: 0)) + + XCTAssertNotEqual(NIOHTTP2Errors.unsupported(info: "info"), + NIOHTTP2Errors.unsupported(info: "notinfo")) + + XCTAssertEqual(NIOHTTP2Errors.unableToSerializeFrame(), + NIOHTTP2Errors.unableToSerializeFrame(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.unableToParseFrame(), + NIOHTTP2Errors.unableToParseFrame(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.missingPseudoHeader("missing"), + NIOHTTP2Errors.missingPseudoHeader("missing", file: "", line: 0)) + + XCTAssertNotEqual(NIOHTTP2Errors.missingPseudoHeader("missing"), + NIOHTTP2Errors.missingPseudoHeader("notmissing")) + + XCTAssertEqual(NIOHTTP2Errors.duplicatePseudoHeader("duplicate"), + NIOHTTP2Errors.duplicatePseudoHeader("duplicate", file: "", line: 0)) + + XCTAssertNotEqual(NIOHTTP2Errors.duplicatePseudoHeader("duplicate"), + NIOHTTP2Errors.duplicatePseudoHeader("notduplicate")) + + XCTAssertEqual(NIOHTTP2Errors.pseudoHeaderAfterRegularHeader("after"), + NIOHTTP2Errors.pseudoHeaderAfterRegularHeader("after", file: "", line: 0)) + + XCTAssertNotEqual(NIOHTTP2Errors.pseudoHeaderAfterRegularHeader("after"), + NIOHTTP2Errors.pseudoHeaderAfterRegularHeader("notafter")) + + XCTAssertEqual(NIOHTTP2Errors.unknownPseudoHeader("unknown"), + NIOHTTP2Errors.unknownPseudoHeader("unknown", file: "", line: 0)) + + XCTAssertNotEqual(NIOHTTP2Errors.unknownPseudoHeader("unknown"), + NIOHTTP2Errors.unknownPseudoHeader("notunknown")) + + XCTAssertEqual(NIOHTTP2Errors.invalidPseudoHeaders([:]), + NIOHTTP2Errors.invalidPseudoHeaders([:], file: "", line: 0)) + + XCTAssertNotEqual(NIOHTTP2Errors.invalidPseudoHeaders([:]), + NIOHTTP2Errors.invalidPseudoHeaders(["not": "empty"])) + + XCTAssertEqual(NIOHTTP2Errors.missingHostHeader(), + NIOHTTP2Errors.missingHostHeader(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.duplicateHostHeader(), + NIOHTTP2Errors.duplicateHostHeader(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.emptyPathHeader(), + NIOHTTP2Errors.emptyPathHeader(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.invalidStatusValue("invalid"), + NIOHTTP2Errors.invalidStatusValue("invalid", file: "", line: 0)) + + XCTAssertNotEqual(NIOHTTP2Errors.invalidStatusValue("invalid"), + NIOHTTP2Errors.invalidStatusValue("notinvalid")) + + XCTAssertEqual(NIOHTTP2Errors.priorityCycle(streamID: .rootStream), + NIOHTTP2Errors.priorityCycle(streamID: .rootStream, file: "", line: 0)) + + XCTAssertNotEqual(NIOHTTP2Errors.priorityCycle(streamID: .rootStream), + NIOHTTP2Errors.priorityCycle(streamID: 1)) + + XCTAssertEqual(NIOHTTP2Errors.trailersWithoutEndStream(streamID: .rootStream), + NIOHTTP2Errors.trailersWithoutEndStream(streamID: .rootStream, file: "", line: 0)) + + XCTAssertNotEqual(NIOHTTP2Errors.trailersWithoutEndStream(streamID: .rootStream), + NIOHTTP2Errors.trailersWithoutEndStream(streamID: 1)) + + XCTAssertEqual(NIOHTTP2Errors.invalidHTTP2HeaderFieldName("fieldName"), + NIOHTTP2Errors.invalidHTTP2HeaderFieldName("fieldName", file: "", line: 0)) + + XCTAssertNotEqual(NIOHTTP2Errors.invalidHTTP2HeaderFieldName("fieldName"), + NIOHTTP2Errors.invalidHTTP2HeaderFieldName("notFieldName")) + + XCTAssertEqual(NIOHTTP2Errors.forbiddenHeaderField(name: "name", value: "value"), + NIOHTTP2Errors.forbiddenHeaderField(name: "name", value: "value", file: "", line: 0)) + + XCTAssertNotEqual(NIOHTTP2Errors.forbiddenHeaderField(name: "name", value: "value"), + NIOHTTP2Errors.forbiddenHeaderField(name: "notname", value: "value")) + + XCTAssertNotEqual(NIOHTTP2Errors.forbiddenHeaderField(name: "name", value: "value"), + NIOHTTP2Errors.forbiddenHeaderField(name: "name", value: "notvalue")) + + XCTAssertEqual(NIOHTTP2Errors.contentLengthViolated(), + NIOHTTP2Errors.contentLengthViolated(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.excessiveEmptyDataFrames(), + NIOHTTP2Errors.excessiveEmptyDataFrames(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.excessivelyLargeHeaderBlock(), + NIOHTTP2Errors.excessivelyLargeHeaderBlock(file: "", line: 0)) + + XCTAssertEqual(NIOHTTP2Errors.noStreamIDAvailable(), + NIOHTTP2Errors.noStreamIDAvailable(file: "", line: 0)) + } + + func testFitsInAnExistentialContainer() { + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + XCTAssertLessThanOrEqual(MemoryLayout.size, 24) + } +} diff --git a/Tests/NIOHTTP2Tests/HTTP2FramePayloadStreamMultiplexerTests.swift b/Tests/NIOHTTP2Tests/HTTP2FramePayloadStreamMultiplexerTests.swift index ac62b438..e1d86c7a 100644 --- a/Tests/NIOHTTP2Tests/HTTP2FramePayloadStreamMultiplexerTests.swift +++ b/Tests/NIOHTTP2Tests/HTTP2FramePayloadStreamMultiplexerTests.swift @@ -167,7 +167,7 @@ final class HTTP2FramePayloadStreamMultiplexerTests: XCTestCase { // At this stage the stream should be closed with the appropriate error code. XCTAssertEqual(closeError as? NIOHTTP2Errors.StreamClosed, - NIOHTTP2Errors.StreamClosed(streamID: streamID, errorCode: .cancel)) + NIOHTTP2Errors.streamClosed(streamID: streamID, errorCode: .cancel)) XCTAssertNoThrow(try self.channel.finish()) } @@ -204,7 +204,7 @@ final class HTTP2FramePayloadStreamMultiplexerTests: XCTestCase { // At this stage the stream should be closed with the appropriate manufactured error code. XCTAssertEqual(closeError as? NIOHTTP2Errors.StreamClosed, - NIOHTTP2Errors.StreamClosed(streamID: streamID, errorCode: .refusedStream)) + NIOHTTP2Errors.streamClosed(streamID: streamID, errorCode: .refusedStream)) XCTAssertNoThrow(try self.channel.finish()) } @@ -433,7 +433,7 @@ final class HTTP2FramePayloadStreamMultiplexerTests: XCTestCase { // Now send the stream closed event. This will fail the close promise. let userEvent = StreamClosedEvent(streamID: streamID, reason: .cancel) self.channel.pipeline.fireUserInboundEventTriggered(userEvent) - XCTAssertEqual(closeError as? NIOHTTP2Errors.StreamClosed, NIOHTTP2Errors.StreamClosed(streamID: streamID, errorCode: .cancel)) + XCTAssertEqual(closeError as? NIOHTTP2Errors.StreamClosed, NIOHTTP2Errors.streamClosed(streamID: streamID, errorCode: .cancel)) XCTAssertNoThrow(try self.channel.finish()) } @@ -655,7 +655,7 @@ final class HTTP2FramePayloadStreamMultiplexerTests: XCTestCase { // Now we're going to deliver a normal close to the stream. let userEvent = StreamClosedEvent(streamID: streamID, reason: .cancel) self.channel.pipeline.fireUserInboundEventTriggered(userEvent) - XCTAssertEqual(writeError as? NIOHTTP2Errors.StreamClosed, NIOHTTP2Errors.StreamClosed(streamID: streamID, errorCode: .cancel)) + XCTAssertEqual(writeError as? NIOHTTP2Errors.StreamClosed, NIOHTTP2Errors.streamClosed(streamID: streamID, errorCode: .cancel)) XCTAssertNoThrow(try self.channel.finish()) } diff --git a/Tests/NIOHTTP2Tests/HTTP2FramePayloadToHTTP1CodecTests.swift b/Tests/NIOHTTP2Tests/HTTP2FramePayloadToHTTP1CodecTests.swift index 73100274..3e3ff49b 100644 --- a/Tests/NIOHTTP2Tests/HTTP2FramePayloadToHTTP1CodecTests.swift +++ b/Tests/NIOHTTP2Tests/HTTP2FramePayloadToHTTP1CodecTests.swift @@ -385,7 +385,7 @@ final class HTTP2FramePayloadToHTTP1CodecTests: XCTestCase { // A basic request. let requestHeaders = HPACKHeaders([(":path", "/post"), (":scheme", "https"), (":authority", "example.org"), ("other", "header")]) XCTAssertThrowsError(try self.channel.writeInbound(HTTP2Frame.FramePayload.headers(.init(headers: requestHeaders)))) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.MissingPseudoHeader, NIOHTTP2Errors.MissingPseudoHeader(":method")) + XCTAssertEqual(error as? NIOHTTP2Errors.MissingPseudoHeader, NIOHTTP2Errors.missingPseudoHeader(":method")) } // We already know there's an error here. @@ -398,7 +398,7 @@ final class HTTP2FramePayloadToHTTP1CodecTests: XCTestCase { // A basic request. let requestHeaders = HPACKHeaders([(":path", "/post"), (":method", "GET"), (":method", "GET"), (":scheme", "https"), (":authority", "example.org"), ("other", "header")]) XCTAssertThrowsError(try self.channel.writeInbound(HTTP2Frame.FramePayload.headers(.init(headers: requestHeaders)))) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.DuplicatePseudoHeader, NIOHTTP2Errors.DuplicatePseudoHeader(":method")) + XCTAssertEqual(error as? NIOHTTP2Errors.DuplicatePseudoHeader, NIOHTTP2Errors.duplicatePseudoHeader(":method")) } // We already know there's an error here. @@ -411,7 +411,7 @@ final class HTTP2FramePayloadToHTTP1CodecTests: XCTestCase { // A basic request. let requestHeaders = HPACKHeaders([(":method", "GET"), (":scheme", "https"), (":authority", "example.org"), ("other", "header")]) XCTAssertThrowsError(try self.channel.writeInbound(HTTP2Frame.FramePayload.headers(.init(headers: requestHeaders)))) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.MissingPseudoHeader, NIOHTTP2Errors.MissingPseudoHeader(":path")) + XCTAssertEqual(error as? NIOHTTP2Errors.MissingPseudoHeader, NIOHTTP2Errors.missingPseudoHeader(":path")) } // We already know there's an error here. @@ -424,7 +424,7 @@ final class HTTP2FramePayloadToHTTP1CodecTests: XCTestCase { // A basic request. let requestHeaders = HPACKHeaders([(":path", "/post"), (":path", "/post"), (":method", "GET"), (":scheme", "https"), (":authority", "example.org"), ("other", "header")]) XCTAssertThrowsError(try self.channel.writeInbound(HTTP2Frame.FramePayload.headers(.init(headers: requestHeaders)))) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.DuplicatePseudoHeader, NIOHTTP2Errors.DuplicatePseudoHeader(":path")) + XCTAssertEqual(error as? NIOHTTP2Errors.DuplicatePseudoHeader, NIOHTTP2Errors.duplicatePseudoHeader(":path")) } // We already know there's an error here. @@ -437,7 +437,7 @@ final class HTTP2FramePayloadToHTTP1CodecTests: XCTestCase { // A basic request. let requestHeaders = HPACKHeaders([(":method", "GET"), (":scheme", "https"), (":path", "/post"), ("other", "header")]) XCTAssertThrowsError(try self.channel.writeInbound(HTTP2Frame.FramePayload.headers(.init(headers: requestHeaders)))) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.MissingPseudoHeader, NIOHTTP2Errors.MissingPseudoHeader(":authority")) + XCTAssertEqual(error as? NIOHTTP2Errors.MissingPseudoHeader, NIOHTTP2Errors.missingPseudoHeader(":authority")) } // We already know there's an error here. @@ -450,7 +450,7 @@ final class HTTP2FramePayloadToHTTP1CodecTests: XCTestCase { // A basic request. let requestHeaders = HPACKHeaders([(":path", "/post"), (":method", "GET"), (":scheme", "https"), (":authority", "example.org"), (":authority", "example.org"), ("other", "header")]) XCTAssertThrowsError(try self.channel.writeInbound(HTTP2Frame.FramePayload.headers(.init(headers: requestHeaders)))) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.DuplicatePseudoHeader, NIOHTTP2Errors.DuplicatePseudoHeader(":authority")) + XCTAssertEqual(error as? NIOHTTP2Errors.DuplicatePseudoHeader, NIOHTTP2Errors.duplicatePseudoHeader(":authority")) } // We already know there's an error here. @@ -463,7 +463,7 @@ final class HTTP2FramePayloadToHTTP1CodecTests: XCTestCase { // A basic request. let requestHeaders = HPACKHeaders([(":method", "GET"), (":authority", "example.org"), (":path", "/post"), ("other", "header")]) XCTAssertThrowsError(try self.channel.writeInbound(HTTP2Frame.FramePayload.headers(.init(headers: requestHeaders)))) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.MissingPseudoHeader, NIOHTTP2Errors.MissingPseudoHeader(":scheme")) + XCTAssertEqual(error as? NIOHTTP2Errors.MissingPseudoHeader, NIOHTTP2Errors.missingPseudoHeader(":scheme")) } // We already know there's an error here. @@ -476,7 +476,7 @@ final class HTTP2FramePayloadToHTTP1CodecTests: XCTestCase { // A basic request. let requestHeaders = HPACKHeaders([(":path", "/post"), (":method", "GET"), (":scheme", "https"), (":scheme", "https"), (":authority", "example.org"), ("other", "header")]) XCTAssertThrowsError(try self.channel.writeInbound(HTTP2Frame.FramePayload.headers(.init(headers: requestHeaders)))) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.DuplicatePseudoHeader, NIOHTTP2Errors.DuplicatePseudoHeader(":scheme")) + XCTAssertEqual(error as? NIOHTTP2Errors.DuplicatePseudoHeader, NIOHTTP2Errors.duplicatePseudoHeader(":scheme")) } // We already know there's an error here. @@ -489,7 +489,7 @@ final class HTTP2FramePayloadToHTTP1CodecTests: XCTestCase { // A basic response. let requestHeaders = HPACKHeaders([("other", "header")]) XCTAssertThrowsError(try self.channel.writeInbound(HTTP2Frame.FramePayload.headers(.init(headers: requestHeaders)))) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.MissingPseudoHeader, NIOHTTP2Errors.MissingPseudoHeader(":status")) + XCTAssertEqual(error as? NIOHTTP2Errors.MissingPseudoHeader, NIOHTTP2Errors.missingPseudoHeader(":status")) } // We already know there's an error here. @@ -502,7 +502,7 @@ final class HTTP2FramePayloadToHTTP1CodecTests: XCTestCase { // A basic request. let requestHeaders = HPACKHeaders([(":status", "200"), (":status", "404"), ("other", "header")]) XCTAssertThrowsError(try self.channel.writeInbound(HTTP2Frame.FramePayload.headers(.init(headers: requestHeaders)))) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.DuplicatePseudoHeader, NIOHTTP2Errors.DuplicatePseudoHeader(":status")) + XCTAssertEqual(error as? NIOHTTP2Errors.DuplicatePseudoHeader, NIOHTTP2Errors.duplicatePseudoHeader(":status")) } // We already know there's an error here. @@ -515,7 +515,7 @@ final class HTTP2FramePayloadToHTTP1CodecTests: XCTestCase { // A basic response. let requestHeaders = HPACKHeaders([(":status", "captivating")]) XCTAssertThrowsError(try self.channel.writeInbound(HTTP2Frame.FramePayload.headers(.init(headers: requestHeaders)))) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.InvalidStatusValue, NIOHTTP2Errors.InvalidStatusValue("captivating")) + XCTAssertEqual(error as? NIOHTTP2Errors.InvalidStatusValue, NIOHTTP2Errors.invalidStatusValue("captivating")) } // We already know there's an error here. @@ -528,12 +528,12 @@ final class HTTP2FramePayloadToHTTP1CodecTests: XCTestCase { // A basic request without Host. let request = HTTPClientRequestPart.head(.init(version: .init(major: 1, minor: 1), method: .GET, uri: "/")) XCTAssertThrowsError(try self.channel.writeOutbound(request)) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.MissingHostHeader, NIOHTTP2Errors.MissingHostHeader()) + XCTAssertEqual(error as? NIOHTTP2Errors.MissingHostHeader, NIOHTTP2Errors.missingHostHeader()) } // We check the channel for an error as the above only checks the promise. XCTAssertThrowsError(try self.channel.finish()) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.MissingHostHeader, NIOHTTP2Errors.MissingHostHeader()) + XCTAssertEqual(error as? NIOHTTP2Errors.MissingHostHeader, NIOHTTP2Errors.missingHostHeader()) } } @@ -546,12 +546,12 @@ final class HTTP2FramePayloadToHTTP1CodecTests: XCTestCase { requestHead.headers.add(name: "Host", value: "cat") let request = HTTPClientRequestPart.head(requestHead) XCTAssertThrowsError(try self.channel.writeOutbound(request)) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.DuplicateHostHeader, NIOHTTP2Errors.DuplicateHostHeader()) + XCTAssertEqual(error as? NIOHTTP2Errors.DuplicateHostHeader, NIOHTTP2Errors.duplicateHostHeader()) } // We check the channel for an error as the above only checks the promise. XCTAssertThrowsError(try self.channel.finish()) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.DuplicateHostHeader, NIOHTTP2Errors.DuplicateHostHeader()) + XCTAssertEqual(error as? NIOHTTP2Errors.DuplicateHostHeader, NIOHTTP2Errors.duplicateHostHeader()) } } diff --git a/Tests/NIOHTTP2Tests/OutboundFlowControlBufferTests.swift b/Tests/NIOHTTP2Tests/OutboundFlowControlBufferTests.swift index 4cb7c5db..7528ee1c 100644 --- a/Tests/NIOHTTP2Tests/OutboundFlowControlBufferTests.swift +++ b/Tests/NIOHTTP2Tests/OutboundFlowControlBufferTests.swift @@ -243,7 +243,7 @@ class OutboundFlowControlBufferTests: XCTestCase { return } for (_, promise) in droppedFrames { - promise?.fail(NIOHTTP2Errors.StreamClosed(streamID: streamOne, errorCode: .protocolError)) + promise?.fail(NIOHTTP2Errors.streamClosed(streamID: streamOne, errorCode: .protocolError)) } XCTAssertThrowsError(try dataPromise.futureResult.wait()) { @@ -374,10 +374,10 @@ class OutboundFlowControlBufferTests: XCTestCase { func testRejectsPrioritySelfDependency() { XCTAssertThrowsError(try self.buffer.priorityUpdate(streamID: 1, priorityData: .init(exclusive: false, dependency: 1, weight: 36))) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.PriorityCycle, NIOHTTP2Errors.PriorityCycle(streamID: 1)) + XCTAssertEqual(error as? NIOHTTP2Errors.PriorityCycle, NIOHTTP2Errors.priorityCycle(streamID: 1)) } XCTAssertThrowsError(try self.buffer.priorityUpdate(streamID: 1, priorityData: .init(exclusive: true, dependency: 1, weight: 36))) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.PriorityCycle, NIOHTTP2Errors.PriorityCycle(streamID: 1)) + XCTAssertEqual(error as? NIOHTTP2Errors.PriorityCycle, NIOHTTP2Errors.priorityCycle(streamID: 1)) } } } diff --git a/Tests/NIOHTTP2Tests/SimpleClientServerFramePayloadStreamTests.swift b/Tests/NIOHTTP2Tests/SimpleClientServerFramePayloadStreamTests.swift index fddbf6bc..30291d34 100644 --- a/Tests/NIOHTTP2Tests/SimpleClientServerFramePayloadStreamTests.swift +++ b/Tests/NIOHTTP2Tests/SimpleClientServerFramePayloadStreamTests.swift @@ -1001,7 +1001,7 @@ class SimpleClientServerFramePayloadStreamTests: XCTestCase { self.interactInMemory(self.clientChannel, self.serverChannel) - XCTAssertNoThrow(try XCTAssertEqual(NIOHTTP2Errors.BadClientMagic(), + XCTAssertNoThrow(try XCTAssertEqual(NIOHTTP2Errors.badClientMagic(), errorSeenPromise.futureResult.wait() as? NIOHTTP2Errors.BadClientMagic)) // The client will get two frames: a SETTINGS frame, and a GOAWAY frame. We don't want to decode these, so we @@ -1201,7 +1201,7 @@ class SimpleClientServerFramePayloadStreamTests: XCTestCase { return } XCTAssertThrowsError(try self.serverChannel.writeInbound(frameData)) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.PriorityCycle, NIOHTTP2Errors.PriorityCycle(streamID: 1)) + XCTAssertEqual(error as? NIOHTTP2Errors.PriorityCycle, NIOHTTP2Errors.priorityCycle(streamID: 1)) } guard let responseFrame = try assertNoThrowWithValue(self.serverChannel.readOutbound(as: ByteBuffer.self)) else { @@ -1233,7 +1233,7 @@ class SimpleClientServerFramePayloadStreamTests: XCTestCase { return } XCTAssertThrowsError(try self.serverChannel.writeInbound(frameData)) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.PriorityCycle, NIOHTTP2Errors.PriorityCycle(streamID: 1)) + XCTAssertEqual(error as? NIOHTTP2Errors.PriorityCycle, NIOHTTP2Errors.priorityCycle(streamID: 1)) } guard let responseFrame = try assertNoThrowWithValue(self.serverChannel.readOutbound(as: ByteBuffer.self)) else { @@ -1264,7 +1264,7 @@ class SimpleClientServerFramePayloadStreamTests: XCTestCase { return } XCTAssertThrowsError(try self.serverChannel.writeInbound(frameData)) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.InvalidHTTP2HeaderFieldName, NIOHTTP2Errors.InvalidHTTP2HeaderFieldName("UPPERCASE")) + XCTAssertEqual(error as? NIOHTTP2Errors.InvalidHTTP2HeaderFieldName, NIOHTTP2Errors.invalidHTTP2HeaderFieldName("UPPERCASE")) } guard let responseFrame = try assertNoThrowWithValue(self.serverChannel.readOutbound(as: ByteBuffer.self)) else { @@ -1296,7 +1296,7 @@ class SimpleClientServerFramePayloadStreamTests: XCTestCase { settingsBuffer.writeBytes(weirdSettingsFrame) XCTAssertThrowsError(try self.clientChannel.writeInbound(settingsBuffer)) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.InvalidSetting, NIOHTTP2Errors.InvalidSetting(setting: HTTP2Setting(parameter: .enablePush, value: 3))) + XCTAssertEqual(error as? NIOHTTP2Errors.InvalidSetting, NIOHTTP2Errors.invalidSetting(setting: HTTP2Setting(parameter: .enablePush, value: 3))) } guard let goAwayFrame = try assertNoThrowWithValue(self.clientChannel.readOutbound(as: ByteBuffer.self)) else { @@ -1453,7 +1453,7 @@ class SimpleClientServerFramePayloadStreamTests: XCTestCase { // The server should have errored. XCTAssertThrowsError(try self.serverChannel.writeInbound(bytes)) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.ExcessiveEmptyDataFrames, NIOHTTP2Errors.ExcessiveEmptyDataFrames()) + XCTAssertEqual(error as? NIOHTTP2Errors.ExcessiveEmptyDataFrames, NIOHTTP2Errors.excessiveEmptyDataFrames()) } guard let serverBytes = try assertNoThrowWithValue(self.serverChannel.readOutbound(as: ByteBuffer.self)) else { @@ -1505,7 +1505,7 @@ class SimpleClientServerFramePayloadStreamTests: XCTestCase { // The server should have errored. XCTAssertThrowsError(try self.serverChannel.writeInbound(bytes)) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.ExcessiveEmptyDataFrames, NIOHTTP2Errors.ExcessiveEmptyDataFrames()) + XCTAssertEqual(error as? NIOHTTP2Errors.ExcessiveEmptyDataFrames, NIOHTTP2Errors.excessiveEmptyDataFrames()) } guard let serverBytes = try assertNoThrowWithValue(self.serverChannel.readOutbound(as: ByteBuffer.self)) else { @@ -1546,7 +1546,7 @@ class SimpleClientServerFramePayloadStreamTests: XCTestCase { return } XCTAssertThrowsError(try self.serverChannel.writeInbound(pingBytes)) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.ExcessiveOutboundFrameBuffering, NIOHTTP2Errors.ExcessiveOutboundFrameBuffering()) + XCTAssertEqual(error as? NIOHTTP2Errors.ExcessiveOutboundFrameBuffering, NIOHTTP2Errors.excessiveOutboundFrameBuffering()) } XCTAssertNoThrow(try self.clientChannel.finish()) @@ -1573,7 +1573,7 @@ class SimpleClientServerFramePayloadStreamTests: XCTestCase { return } XCTAssertThrowsError(try self.serverChannel.writeInbound(settingsBytes)) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.ExcessiveOutboundFrameBuffering, NIOHTTP2Errors.ExcessiveOutboundFrameBuffering()) + XCTAssertEqual(error as? NIOHTTP2Errors.ExcessiveOutboundFrameBuffering, NIOHTTP2Errors.excessiveOutboundFrameBuffering()) } XCTAssertNoThrow(try self.clientChannel.finish()) @@ -1677,7 +1677,7 @@ class SimpleClientServerFramePayloadStreamTests: XCTestCase { return } XCTAssertThrowsError(try self.serverChannel.writeInbound(frameData)) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.UnableToParseFrame, NIOHTTP2Errors.UnableToParseFrame()) + XCTAssertEqual(error as? NIOHTTP2Errors.UnableToParseFrame, NIOHTTP2Errors.unableToParseFrame()) } guard let responseFrame = try assertNoThrowWithValue(self.serverChannel.readOutbound(as: ByteBuffer.self)) else { @@ -1728,7 +1728,7 @@ class SimpleClientServerFramePayloadStreamTests: XCTestCase { // But if we send one more frame, that will be treated as a violation of SETTINGS_MAX_HEADER_LIST_SIZE. XCTAssertThrowsError(try self.serverChannel.writeInbound(firstBuffer.getSlice(at: firstBuffer.writerIndex - 10, length: 10)!)) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.ExcessivelyLargeHeaderBlock, NIOHTTP2Errors.ExcessivelyLargeHeaderBlock()) + XCTAssertEqual(error as? NIOHTTP2Errors.ExcessivelyLargeHeaderBlock, NIOHTTP2Errors.excessivelyLargeHeaderBlock()) } guard let responseFrame = try assertNoThrowWithValue(self.serverChannel.readOutbound(as: ByteBuffer.self)) else { XCTFail("Did not receive response frame") @@ -1763,7 +1763,7 @@ class SimpleClientServerFramePayloadStreamTests: XCTestCase { // This frame will be treated as a violation of SETTINGS_MAX_HEADER_LIST_SIZE. XCTAssertThrowsError(try self.serverChannel.writeInbound(buffer)) { error in - XCTAssertEqual(error as? NIOHTTP2Errors.ExcessivelyLargeHeaderBlock, NIOHTTP2Errors.ExcessivelyLargeHeaderBlock()) + XCTAssertEqual(error as? NIOHTTP2Errors.ExcessivelyLargeHeaderBlock, NIOHTTP2Errors.excessivelyLargeHeaderBlock()) } guard let responseFrame = try assertNoThrowWithValue(self.serverChannel.readOutbound(as: ByteBuffer.self)) else { XCTFail("Did not receive response frame")