leyline-http 0.1.5

HTTP client that impersonates Chrome, Firefox, and Safari on the wire: TLS (JA3/JA4), HTTP/2, and HTTP/3 fingerprints
Documentation
use bytes::{BufMut, Bytes};

use super::{FrameHeader, FrameType};
use crate::h2::H2Error;
use crate::h2::error::ErrorCode;

pub mod flags {
    pub const ACK: u8 = 0x1;
}

#[derive(Debug)]
pub struct PingFrame {
    pub ack: bool,
    pub payload: [u8; 8],
}

impl PingFrame {
    pub fn parse(header: FrameHeader, payload: Bytes) -> Result<Self, H2Error> {
        if header.stream_id != 0 {
            return Err(H2Error::Connection {
                code: ErrorCode::ProtocolError,
                reason: "PING on non-zero stream".into(),
            });
        }
        if payload.len() != 8 {
            return Err(H2Error::Connection {
                code: ErrorCode::FrameSizeError,
                reason: format!("PING must be 8 bytes, got {}", payload.len()),
            });
        }

        let ack = header.flags & flags::ACK != 0;
        let mut data = [0u8; 8];
        data.copy_from_slice(&payload[..8]);

        Ok(Self { ack, payload: data })
    }

    pub fn encode(&self, buf: &mut impl BufMut) {
        let header = FrameHeader {
            length: 8,
            frame_type: FrameType::Ping as u8,
            flags: if self.ack { flags::ACK } else { 0 },
            stream_id: 0,
        };
        header.encode(buf);
        buf.put_slice(&self.payload);
    }
}