1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use std::{fmt, time};

use crate::http::body::MessageBody;
use crate::http::message::{RequestHeadType, ResponseHead};
use crate::http::payload::Payload;
use crate::io::{types::HttpProtocol, IoBoxed};

use super::{error::SendRequestError, 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"),
        }
    }
}

#[doc(hidden)]
/// HTTP client connection
pub 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(_)) => write!(f, "H1Connection"),
            Some(ConnectionType::H2(_)) => write!(f, "H2Connection"),
            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(mut pool) = self.pool {
            pool.release(
                Self {
                    io: self.io,
                    created: self.created,
                    pool: None,
                },
                close,
            );
        }
    }

    pub(super) fn into_inner(self) -> (ConnectionType, time::Instant, Option<Acquired>) {
        (self.io.unwrap(), self.created, self.pool)
    }

    pub 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<B: MessageBody + 'static, H: Into<RequestHeadType>>(
        mut self,
        head: H,
        body: B,
    ) -> Result<(ResponseHead, Payload), SendRequestError> {
        match self.io.take().unwrap() {
            ConnectionType::H1(io) => {
                h1proto::send_request(io, head.into(), body, self.created, self.pool).await
            }
            ConnectionType::H2(io) => h2proto::send_request(io, head.into(), body).await,
        }
    }
}