leyline-http 0.1.1

HTTP client that mimics browsers on the wire
Documentation
use std::collections::VecDeque;
use std::sync::atomic::AtomicU64;
use std::time::Instant;

use crate::h2::client::H2Client;
#[cfg(feature = "http3")]
use crate::quic::H3Client;

use crate::pool::h1::H1Io;

#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct TlsInfo {
    pub peer_cert_der: Option<Vec<u8>>,
    pub version: Option<String>,
    pub cipher: Option<String>,
}

pub(crate) struct Opened<C> {
    pub(crate) conn: C,
    pub(crate) tls: TlsInfo,
    pub(crate) started: Instant,
    pub(crate) connect_ms: Option<u32>,
}

impl<C> Opened<C> {
    pub(crate) fn pooled((conn, tls): (C, TlsInfo)) -> Self {
        Self {
            conn,
            tls,
            started: Instant::now(),
            connect_ms: None,
        }
    }

    pub(crate) fn fresh((conn, tls): (C, TlsInfo), started: Instant) -> Self {
        Self {
            conn,
            tls,
            started,
            connect_ms: Some(crate::ResponseTiming::millis(started)),
        }
    }
}

#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub(crate) enum Transport {
    Tcp,
    #[cfg_attr(not(feature = "http3"), allow(dead_code))]
    Quic,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub(crate) struct PoolKey {
    pub(crate) host: String,
    pub(crate) port: u16,
    pub(crate) scheme: String,
    pub(crate) proxy: Option<String>,
    pub(crate) transport: Transport,
    pub(crate) partition: u64,
}

pub struct H1Slot {
    pub(crate) io: Box<dyn H1Io>,
}

pub(crate) enum PooledConn {
    H2 {
        handle: H2Client,
        last_use: Instant,
        tls: TlsInfo,
    },
    H1 {
        idle: VecDeque<(H1Slot, Instant)>,
        last_use: Instant,
        tls: TlsInfo,
    },
    #[cfg(feature = "http3")]
    H3 {
        handle: H3Client,
        last_use: Instant,
        tls: TlsInfo,
    },
}

impl PooledConn {
    pub(crate) fn last_use(&self) -> Instant {
        match self {
            PooledConn::H2 { last_use, .. } | PooledConn::H1 { last_use, .. } => *last_use,
            #[cfg(feature = "http3")]
            PooledConn::H3 { last_use, .. } => *last_use,
        }
    }

    pub(crate) fn set_last_use(&mut self, now: Instant) {
        match self {
            PooledConn::H2 { last_use, .. } | PooledConn::H1 { last_use, .. } => *last_use = now,
            #[cfg(feature = "http3")]
            PooledConn::H3 { last_use, .. } => *last_use = now,
        }
    }

    pub(crate) fn is_dead(&self) -> bool {
        match self {
            PooledConn::H2 { handle, .. } => handle.is_closed(),
            PooledConn::H1 { idle, .. } => idle.is_empty(),
            #[cfg(feature = "http3")]
            PooledConn::H3 { handle, .. } => handle.is_closed(),
        }
    }
}

#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[non_exhaustive]
pub struct PoolStats {
    pub entries: usize,
    pub max_connections: usize,
    pub h2_hits: u64,
    pub h2_misses: u64,
    pub h1_hits: u64,
    pub h1_misses: u64,
    pub h3_hits: u64,
    pub h3_misses: u64,
    pub evictions_idle: u64,
    pub evictions_lru: u64,
    pub evictions_dead: u64,
    pub stale_probed: u64,
    pub h2_ping_failures: u64,
    pub installs: u64,
    pub busy: usize,
    pub idle: usize,
}

#[derive(Default)]
pub(crate) struct PoolCounters {
    pub(crate) h2_hits: AtomicU64,
    pub(crate) h2_misses: AtomicU64,
    pub(crate) h1_hits: AtomicU64,
    pub(crate) h1_misses: AtomicU64,
    pub(crate) h3_hits: AtomicU64,
    pub(crate) h3_misses: AtomicU64,
    pub(crate) evictions_idle: AtomicU64,
    pub(crate) evictions_lru: AtomicU64,
    pub(crate) evictions_dead: AtomicU64,
    pub(crate) stale_probed: AtomicU64,
    pub(crate) h2_ping_failures: AtomicU64,
    pub(crate) installs: AtomicU64,
}