Repository: apple/swift-nio
File: Sources/NIOHTTP1/NIOTypedHTTPClientUpgradeHandler.swift (Swift)

Code before:

    public func write(context: ChannelHandlerContext, data: NIOAny, promise: EventLoopPromise<Void>?) {
        switch self.stateMachine.write() {
        case .failWrite(let error):
            promise?.fail(error)

        case .forwardWrite:
            context.write(data, promise: promise)
        }
    }

    public func channelRead(context: ChannelHandlerContext, data: NIOAny) {
        switch self.stateMachine.channelReadData(data) {
        case .unwrapData:
            let responsePart = Self.unwrapInboundIn(data)
            self.channelRead(context: context, responsePart: responsePart)

        case .fireChannelRead:
            context.fireChannelRead(data)

        case .none:
            break
        }
    }

    public func errorCaught(context: ChannelHandlerContext, error: any Error) {
        self.upgradeResultPromise.fail(error)
    }

    private func channelRead(context: ChannelHandlerContext, responsePart: HTTPClientResponsePart) {
        switch self.stateMachine.channelReadResponsePart(responsePart) {
        case .fireErrorCaughtAndRemoveHandler(let error):
            self.upgradeResultPromise.fail(error)
            context.fireErrorCaught(error)
            context.pipeline.syncOperations.removeHandler(self, promise: nil)

        case .runNotUpgradingInitializer:
            self.notUpgradingCompletionHandler(context.channel)
                .hop(to: context.eventLoop)
                .assumeIsolated()
                .whenComplete { result in
                    self.upgradingHandlerCompleted(context: context, result)
                }

        case .startUpgrading(let upgrader, let responseHead):
            self.startUpgrading(
                context: context,
                upgrader: upgrader,
                responseHead: responseHead
            )


Review comment (suggestion):
We should probably fire the error on as well, to avoid breaking any systems that were relying on this.

Code after:

    public func write(context: ChannelHandlerContext, data: NIOAny, promise: EventLoopPromise<Void>?) {
        switch self.stateMachine.write() {
        case .failWrite(let error):
            promise?.fail(error)

        case .forwardWrite:
            context.write(data, promise: promise)
        }
    }

    public func channelRead(context: ChannelHandlerContext, data: NIOAny) {
        switch self.stateMachine.channelReadData(data) {
        case .unwrapData:
            let responsePart = Self.unwrapInboundIn(data)
            self.channelRead(context: context, responsePart: responsePart)

        case .fireChannelRead:
            context.fireChannelRead(data)

        case .none:
            break
        }
    }

    public func errorCaught(context: ChannelHandlerContext, error: any Error) {
        self.upgradeResultPromise.fail(error)
        context.fireErrorCaught(error)
    }

    private func channelRead(context: ChannelHandlerContext, responsePart: HTTPClientResponsePart) {
        switch self.stateMachine.channelReadResponsePart(responsePart) {
        case .fireErrorCaughtAndRemoveHandler(let error):
            self.upgradeResultPromise.fail(error)
            context.fireErrorCaught(error)
            context.pipeline.syncOperations.removeHandler(self, promise: nil)

        case .runNotUpgradingInitializer:
            self.notUpgradingCompletionHandler(context.channel)
                .hop(to: context.eventLoop)
                .assumeIsolated()
                .whenComplete { result in
                    self.upgradingHandlerCompleted(context: context, result)
                }

        case .startUpgrading(let upgrader, let responseHead):
            self.startUpgrading(
                context: context,
                upgrader: upgrader,
                responseHead: responseHead
            )