ntex 4.0.0-beta.15

Framework for composable network services
use std::{fmt, time};

use crate::http::body::Body;
use crate::http::{Payload, ResponseHead, Version};
use crate::io::IoBoxed;
#[cfg(test)]
use crate::io::types::HttpProtocol;
use crate::{error::Error, time::Millis};

use super::{ClientRawRequest, error::ClientError, h1proto, h2proto, pool::Acquired};

pub(super) enum ConnectionType {
    H1(IoBoxed),
    H2(h2proto::H2Client),
}

impl fmt::Debug for ConnectionType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ConnectionType::H1(_) => write!(f, "http/1"),
            ConnectionType::H2(_) => write!(f, "http/2"),
        }
    }
}

pub(crate) struct Connection {
    io: Option<ConnectionType>,
    created: time::Instant,
    pool: Option<Acquired>,
}

impl fmt::Debug for Connection {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match &self.io {
            Some(ConnectionType::H1(io)) => write!(f, "{}: Connection(h1)", io.tag()),
            Some(ConnectionType::H2(io)) => write!(f, "{}: Connection(h2)", io.tag()),
            None => write!(f, "Connection(Empty)"),
        }
    }
}

impl Connection {
    pub(super) fn new(io: ConnectionType, created: time::Instant, pool: Option<Acquired>) -> Self {
        Self {
            pool,
            created,
            io: Some(io),
        }
    }

    pub(super) fn release(self, close: bool) {
        if let (Some(pool), Some(ConnectionType::H1(io))) = (self.pool, self.io) {
            pool.release(io, self.created, close);
        } else {
            log::debug!("http pool is not set, dropping connection");
        }
    }

    #[cfg(test)]
    pub(super) fn protocol(&self) -> HttpProtocol {
        match self.io {
            Some(ConnectionType::H1(_)) => HttpProtocol::Http1,
            Some(ConnectionType::H2(_)) => HttpProtocol::Http2,
            None => HttpProtocol::Unknown,
        }
    }

    pub(super) async fn send_request(
        mut self,
        mut req: ClientRawRequest,
        body: Body,
        timeout: Millis,
    ) -> Result<(ResponseHead, Payload), Error<ClientError>> {
        match self.io.take().unwrap() {
            ConnectionType::H1(io) => {
                req.head.version = Version::HTTP_11;
                h1proto::send_request(io, req, body, self.created, timeout, self.pool).await
            }
            ConnectionType::H2(io) => {
                req.head.version = Version::HTTP_2;
                h2proto::send_request(io, req, body, timeout).await
            }
        }
    }
}