mutating func sendWindowUpdate()

in Sources/NIOHTTP2/StreamStateMachine.swift [727:783]


    mutating func sendWindowUpdate(windowIncrement: UInt32) -> StateMachineResultWithStreamEffect {
        let windowEffect: StreamStateChange

        do {
            // RFC 7540 does not limit the states in which WINDOW_UDPATE frames can be sent. For this reason we need to be
            // fairly conservative about applying limits. In essence, we allow sending WINDOW_UPDATE frames in all but the
            // following states:
            //
            // - idle, because the stream hasn't been created yet so the stream ID is invalid
            // - reservedLocal, because the remote peer will never be able to send data
            // - halfClosedRemoteLocalIdle and halfClosedRemoteLocalActive, because the remote peer has sent END_STREAM and
            //     can send no further data
            // - closed, because the entire stream is closed now
            switch self.state {
            case .reservedRemote(remoteWindow: var remoteWindow):
                try remoteWindow.windowUpdate(by: windowIncrement)
                self.state = .reservedRemote(remoteWindow: remoteWindow)
                windowEffect = .windowSizeChange(.init(streamID: self.streamID, localStreamWindowSize: nil, remoteStreamWindowSize: Int(remoteWindow)))

            case .halfOpenLocalPeerIdle(localWindow: let localWindow, localContentLength: let localContentLength, remoteWindow: var remoteWindow):
                try remoteWindow.windowUpdate(by: windowIncrement)
                self.state = .halfOpenLocalPeerIdle(localWindow: localWindow, localContentLength: localContentLength, remoteWindow: remoteWindow)
                windowEffect = .windowSizeChange(.init(streamID: self.streamID, localStreamWindowSize: Int(localWindow), remoteStreamWindowSize: Int(remoteWindow)))

            case .halfOpenRemoteLocalIdle(localWindow: let localWindow, remoteContentLength: let remoteContentLength, remoteWindow: var remoteWindow):
                try remoteWindow.windowUpdate(by: windowIncrement)
                self.state = .halfOpenRemoteLocalIdle(localWindow: localWindow, remoteContentLength: remoteContentLength, remoteWindow: remoteWindow)
                windowEffect = .windowSizeChange(.init(streamID: self.streamID, localStreamWindowSize: Int(localWindow), remoteStreamWindowSize: Int(remoteWindow)))

            case .fullyOpen(localRole: let localRole, localContentLength: let localContentLength, remoteContentLength: let remoteContentLength, localWindow: let localWindow, remoteWindow: var remoteWindow):
                try remoteWindow.windowUpdate(by: windowIncrement)
                self.state = .fullyOpen(localRole: localRole, localContentLength: localContentLength, remoteContentLength: remoteContentLength, localWindow: localWindow, remoteWindow: remoteWindow)
                windowEffect = .windowSizeChange(.init(streamID: self.streamID, localStreamWindowSize: Int(localWindow), remoteStreamWindowSize: Int(remoteWindow)))

            case .halfClosedLocalPeerIdle(remoteWindow: var remoteWindow):
                try remoteWindow.windowUpdate(by: windowIncrement)
                self.state = .halfClosedLocalPeerIdle(remoteWindow: remoteWindow)
                windowEffect = .windowSizeChange(.init(streamID: self.streamID, localStreamWindowSize: nil, remoteStreamWindowSize: Int(remoteWindow)))

            case .halfClosedLocalPeerActive(localRole: let localRole, initiatedBy: let initiatedBy, remoteContentLength: let remoteContentLength, remoteWindow: var remoteWindow):
                try remoteWindow.windowUpdate(by: windowIncrement)
                self.state = .halfClosedLocalPeerActive(localRole: localRole, initiatedBy: initiatedBy, remoteContentLength: remoteContentLength, remoteWindow: remoteWindow)
                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)
            }
        } catch let error where error is NIOHTTP2Errors.InvalidFlowControlWindowSize {
            return .init(result: .streamError(streamID: self.streamID, underlyingError: error, type: .flowControlError), effect: nil)
        } catch let error where error is NIOHTTP2Errors.InvalidWindowIncrementSize {
            return .init(result: .streamError(streamID: self.streamID, underlyingError: error, type: .protocolError), effect: nil)
        } catch {
            preconditionFailure("Unexpected error: \(error)")
        }

        return .init(result: .succeed, effect: windowEffect)
    }