mutating func receivePushPromise()

in Sources/NIOHTTP2/ConnectionStateMachine/ConnectionStateMachine.swift [1032:1094]


    mutating func receivePushPromise(originalStreamID: HTTP2StreamID, childStreamID: HTTP2StreamID, headers: HPACKHeaders) -> StateMachineResultWithEffect {
        // In states that support a push promise we have two steps. Firstly, we want to create the child stream; then we want to
        // pass the PUSH_PROMISE frame through the stream state machine for the parent stream.
        //
        // The reason we do things in this order is that if for any reason the PUSH_PROMISE frame is invalid on the parent stream,
        // we want to take out both the child stream and the parent stream. We can only do that if we have a child stream state to
        // modify. For this reason, we unconditionally allow the remote peer to consume the stream. The only case where this is *not*
        // true is when the child stream itself cannot be validly created, because the stream ID used by the remote peer is invalid.
        // In this case this is a connection error, anyway, so we don't worry too much about it.
        switch self.state {
        case .prefaceReceived(var state):
            return self.avoidingStateMachineCoW { newState in
                let result = state.receivePushPromise(originalStreamID: originalStreamID, childStreamID: childStreamID, headers: headers)
                newState = .prefaceReceived(state)
                return result
            }

        case .active(var state):
            return self.avoidingStateMachineCoW { newState in
                let result = state.receivePushPromise(originalStreamID: originalStreamID, childStreamID: childStreamID, headers: headers)
                newState = .active(state)
                return result
            }

        case .locallyQuiesced(var state):
            return self.avoidingStateMachineCoW { newState in
                let result = state.receivePushPromise(originalStreamID: originalStreamID, childStreamID: childStreamID, headers: headers)
                newState = .locallyQuiesced(state)
                return result
            }

        case .remotelyQuiesced(var state):
            return self.avoidingStateMachineCoW { newState in
                let result = state.receivePushPromise(originalStreamID: originalStreamID, childStreamID: childStreamID, headers: headers)
                newState = .remotelyQuiesced(state)
                return result
            }

        case .bothQuiescing(var state):
            return self.avoidingStateMachineCoW { newState in
                let result = state.receivePushPromise(originalStreamID: originalStreamID, childStreamID: childStreamID, headers: headers)
                newState = .bothQuiescing(state)
                return result
            }

        case .quiescingPrefaceReceived(var state):
            return self.avoidingStateMachineCoW { newState in
                let result = state.receivePushPromise(originalStreamID: originalStreamID, childStreamID: childStreamID, headers: headers)
                newState = .quiescingPrefaceReceived(state)
                return result
            }

        case .idle, .prefaceSent, .quiescingPrefaceSent:
            // We're waiting for the remote preface.
            return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.missingPreface(), type: .protocolError), effect: nil)

        case .fullyQuiesced:
            return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.ioOnClosedConnection(), type: .protocolError), effect: nil)

        case .modifying:
            preconditionFailure("Must not be left in modifying state")
        }
    }