use std::net::SocketAddr;
use std::sync::Arc;
use std::task::{Context, Poll};
use std::time::Duration;
use crate::clock::Instant;
pub(crate) enum HttpConnection<B> {
H1(hyper::client::conn::http1::SendRequest<B>),
H2(hyper::client::conn::http2::SendRequest<B>),
#[cfg(all(feature = "http3", feature = "rustls"))]
H3(h3::client::SendRequest<h3_quinn::OpenStreams, bytes::Bytes>),
}
pub(crate) struct PooledConnection<B> {
pub(crate) conn: HttpConnection<B>,
pub(crate) remote_addr: Option<SocketAddr>,
pub(crate) tls_info: Option<crate::tls::TlsInfo>,
pub(crate) tls_handshake_duration: Option<Duration>,
pub(crate) sans: Arc<[String]>,
pub(crate) created_at: Instant,
pub(crate) requests_served: u32,
pub(crate) bytes_sent: u64,
pub(crate) bytes_received: u64,
pub(crate) is_multiplex_clone: bool,
pub(crate) upgrade_handle_local: Option<crate::upgrade::UpgradeHandleLocal>,
}
impl<B> PooledConnection<B> {
pub(crate) fn new_h1(sender: hyper::client::conn::http1::SendRequest<B>) -> Self {
Self {
conn: HttpConnection::H1(sender),
remote_addr: None,
tls_info: None,
tls_handshake_duration: None,
sans: Arc::from([]),
created_at: Instant::now(),
requests_served: 0,
bytes_sent: 0,
bytes_received: 0,
is_multiplex_clone: false,
upgrade_handle_local: None,
}
}
pub(crate) fn new_h2(sender: hyper::client::conn::http2::SendRequest<B>) -> Self {
Self {
conn: HttpConnection::H2(sender),
remote_addr: None,
tls_info: None,
tls_handshake_duration: None,
sans: Arc::from([]),
created_at: Instant::now(),
requests_served: 0,
bytes_sent: 0,
bytes_received: 0,
is_multiplex_clone: false,
upgrade_handle_local: None,
}
}
#[cfg(all(feature = "http3", feature = "rustls"))]
pub(crate) fn new_h3(
sender: h3::client::SendRequest<h3_quinn::OpenStreams, bytes::Bytes>,
) -> Self {
Self {
conn: HttpConnection::H3(sender),
remote_addr: None,
tls_info: None,
tls_handshake_duration: None,
sans: Arc::from([]),
created_at: Instant::now(),
requests_served: 0,
bytes_sent: 0,
bytes_received: 0,
is_multiplex_clone: false,
upgrade_handle_local: None,
}
}
pub(crate) fn is_ready(&self) -> bool {
match &self.conn {
HttpConnection::H1(s) => s.is_ready(),
HttpConnection::H2(s) => s.is_ready(),
#[cfg(all(feature = "http3", feature = "rustls"))]
HttpConnection::H3(s) => {
use h3::ConnectionState as _;
!s.is_closing() && s.get_conn_error().is_none()
}
}
}
pub(crate) fn is_h1(&self) -> bool {
matches!(&self.conn, HttpConnection::H1(_))
}
pub(crate) fn is_h2_or_h3(&self) -> bool {
match &self.conn {
HttpConnection::H1(_) => false,
HttpConnection::H2(_) => true,
#[cfg(all(feature = "http3", feature = "rustls"))]
HttpConnection::H3(_) => true,
}
}
pub(crate) fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<bool> {
match &mut self.conn {
HttpConnection::H1(s) => match s.poll_ready(cx) {
Poll::Ready(Ok(())) => Poll::Ready(true),
Poll::Ready(Err(_)) => Poll::Ready(false),
Poll::Pending => Poll::Pending,
},
HttpConnection::H2(s) => {
let _ = s;
Poll::Ready(true)
}
#[cfg(all(feature = "http3", feature = "rustls"))]
HttpConnection::H3(_) => Poll::Ready(true),
}
}
}
impl<B: 'static> PooledConnection<B> {
pub(crate) fn clone_for_multiplex(&self) -> Option<Self> {
let conn = match &self.conn {
HttpConnection::H1(_) => return None,
HttpConnection::H2(s) => HttpConnection::H2(s.clone()),
#[cfg(all(feature = "http3", feature = "rustls"))]
HttpConnection::H3(s) => HttpConnection::H3(s.clone()),
};
Some(Self {
conn,
remote_addr: self.remote_addr,
tls_info: self.tls_info.clone(),
tls_handshake_duration: self.tls_handshake_duration,
sans: self.sans.clone(),
created_at: self.created_at,
requests_served: 0,
bytes_sent: 0,
bytes_received: 0,
is_multiplex_clone: true,
upgrade_handle_local: None,
})
}
}