mutating func encode()

in Sources/NIOHTTP2/HTTP2FrameParser.swift [997:1187]


    mutating func encode(frame: HTTP2Frame, to buf: inout ByteBuffer) throws -> IOData? {
        // note our starting point
        let start = buf.writerIndex

//      +-----------------------------------------------+
//      |                 Length (24)                   |
//      +---------------+---------------+---------------+
//      |   Type (8)    |   Flags (8)   |
//      +-+-------------+---------------+-------------------------------+
//      |R|                 Stream Identifier (31)                      |
//      +=+=============================================================+
//      |                   Frame Payload (0...)                      ...
//      +---------------------------------------------------------------+

        // skip 24-bit length for now, we'll fill that in later
        buf.moveWriterIndex(forwardBy: 3)

        // 8-bit type
        buf.writeInteger(frame.payload.code)

        // skip the 8 bit flags for now, we'll fill it in later as well.
        let flagsIndex = buf.writerIndex
        var flags = FrameFlags()
        buf.moveWriterIndex(forwardBy: 1)

        // 32-bit stream identifier -- ensuring the top bit is empty
        buf.writeInteger(Int32(frame.streamID))

        // frame payload follows, which depends on the frame type itself
        let payloadStart = buf.writerIndex
        let extraFrameData: IOData?
        let payloadSize: Int

        switch frame.payload {
        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")
            }

            if dataContent.endStream {
                flags.insert(.endStream)
            }
            extraFrameData = dataContent.data
            payloadSize = dataContent.data.readableBytes

        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")
            }

            flags.insert(.endHeaders)
            if headerData.endStream {
                flags.insert(.endStream)
            }

            if let priority = headerData.priorityData {
                flags.insert(.priority)
                var dependencyRaw = UInt32(priority.dependency)
                if priority.exclusive {
                    dependencyRaw |= 0x8000_0000
                }
                buf.writeInteger(dependencyRaw)
                buf.writeInteger(priority.weight)
            }

            try self.headerEncoder.encode(headers: headerData.headers, to: &buf)
            payloadSize = buf.writerIndex - payloadStart
            extraFrameData = nil

        case .priority(let priorityData):
            var raw = UInt32(priorityData.dependency)
            if priorityData.exclusive {
                raw |= 0x8000_0000
            }
            buf.writeInteger(raw)
            buf.writeInteger(priorityData.weight)

            extraFrameData = nil
            payloadSize = 5

        case .rstStream(let errcode):
            buf.writeInteger(UInt32(errcode.networkCode))

            payloadSize = 4
            extraFrameData = nil

        case .settings(.settings(let settings)):
            for setting in settings {
                buf.writeInteger(setting.parameter.networkRepresentation)
                buf.writeInteger(setting._value)
            }

            payloadSize = settings.count * 6
            extraFrameData = nil

        case .settings(.ack):
            payloadSize = 0
            extraFrameData = nil
            flags.insert(.ack)

        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")
            }

            let streamVal: UInt32 = UInt32(pushPromiseData.pushedStreamID)
            buf.writeInteger(streamVal)

            try self.headerEncoder.encode(headers: pushPromiseData.headers, to: &buf)

            payloadSize = buf.writerIndex - payloadStart
            extraFrameData = nil
            flags.insert(.endHeaders)

        case .ping(let pingData, let ack):
            withUnsafeBytes(of: pingData.bytes) { ptr -> Void in
                _ = buf.writeBytes(ptr)
            }

            if ack {
                flags.insert(.ack)
            }

            payloadSize = 8
            extraFrameData = nil

        case .goAway(let lastStreamID, let errorCode, let opaqueData):
            let streamVal: UInt32 = UInt32(lastStreamID) & ~0x8000_0000
            buf.writeInteger(streamVal)
            buf.writeInteger(UInt32(errorCode.networkCode))

            if let data = opaqueData {
                payloadSize = data.readableBytes + 8
                extraFrameData = .byteBuffer(data)
            } else {
                payloadSize = 8
                extraFrameData = nil
            }

        case .windowUpdate(let size):
            buf.writeInteger(UInt32(size) & ~0x8000_0000)
            payloadSize = 4
            extraFrameData = nil

        case .alternativeService(let origin, let field):
            if let org = origin {
                buf.moveWriterIndex(forwardBy: 2)
                let start = buf.writerIndex
                buf.writeString(org)
                buf.setInteger(UInt16(buf.writerIndex - start), at: payloadStart)
            } else {
                buf.writeInteger(UInt16(0))
            }

            if let value = field {
                payloadSize = buf.writerIndex - payloadStart + value.readableBytes
                extraFrameData = .byteBuffer(value)
            } else {
                payloadSize = buf.writerIndex - payloadStart
                extraFrameData = nil
            }

        case .origin(let origins):
            for origin in origins {
                let sizeLoc = buf.writerIndex
                buf.moveWriterIndex(forwardBy: 2)

                let start = buf.writerIndex
                buf.writeString(origin)
                buf.setInteger(UInt16(buf.writerIndex - start), at: sizeLoc)
            }

            payloadSize = buf.writerIndex - payloadStart
            extraFrameData = nil
        }

        // Confirm we're not about to violate SETTINGS_MAX_FRAME_SIZE.
        guard payloadSize <= Int(self.maxFrameSize) else {
            throw InternalError.codecError(code: .frameSizeError)
        }

        // Write the frame data. This is the payload size and the flags byte.
        buf.writePayloadSize(payloadSize, at: start)
        buf.setInteger(flags.rawValue, at: flagsIndex)

        // all bytes to write are in the provided buffer now
        return extraFrameData
    }