1use std::net::SocketAddr;
4
5use crate::error::HttpError;
6use crate::h1_conn::H1Conn;
7use crate::h2_conn::H2AsyncConn;
8use crate::request::RequestBuilder;
9use crate::response::Response;
10use crate::streaming::StreamingResponse;
11
12enum ConnectionInner {
13 H2(Box<H2AsyncConn>),
14 H1(H1Conn),
15}
16
17pub struct HttpClient {
27 inner: ConnectionInner,
28 host: String,
29}
30
31impl HttpClient {
32 pub async fn connect_h2(addr: SocketAddr, host: &str) -> Result<Self, HttpError> {
34 let h2 = H2AsyncConn::connect(addr, host).await?;
35 Ok(Self {
36 inner: ConnectionInner::H2(Box::new(h2)),
37 host: host.to_string(),
38 })
39 }
40
41 pub async fn connect_h2_with_timeout(
43 addr: SocketAddr,
44 host: &str,
45 timeout_ms: u64,
46 ) -> Result<Self, HttpError> {
47 let h2 = H2AsyncConn::connect_with_timeout(addr, host, timeout_ms).await?;
48 Ok(Self {
49 inner: ConnectionInner::H2(Box::new(h2)),
50 host: host.to_string(),
51 })
52 }
53
54 pub async fn connect_h1(addr: SocketAddr, host: &str) -> Result<Self, HttpError> {
56 let h1 = H1Conn::connect_tls(addr, host).await?;
57 Ok(Self {
58 inner: ConnectionInner::H1(h1),
59 host: host.to_string(),
60 })
61 }
62
63 pub async fn connect_h1_plain(addr: SocketAddr, host: &str) -> Result<Self, HttpError> {
65 let h1 = H1Conn::connect_plain(addr, host).await?;
66 Ok(Self {
67 inner: ConnectionInner::H1(h1),
68 host: host.to_string(),
69 })
70 }
71
72 pub fn get(&mut self, path: &str) -> RequestBuilder<'_> {
74 RequestBuilder::new(self, "GET", path)
75 }
76
77 pub fn post(&mut self, path: &str) -> RequestBuilder<'_> {
79 RequestBuilder::new(self, "POST", path)
80 }
81
82 pub fn put(&mut self, path: &str) -> RequestBuilder<'_> {
84 RequestBuilder::new(self, "PUT", path)
85 }
86
87 pub fn delete(&mut self, path: &str) -> RequestBuilder<'_> {
89 RequestBuilder::new(self, "DELETE", path)
90 }
91
92 pub(crate) async fn send_request(
94 &mut self,
95 method: &str,
96 path: &str,
97 extra_headers: &[(&str, &str)],
98 body: Option<&[u8]>,
99 ) -> Result<Response, HttpError> {
100 match &mut self.inner {
101 ConnectionInner::H2(h2) => {
102 h2.send_request(method, path, &self.host, extra_headers, body)
103 .await
104 }
105 ConnectionInner::H1(h1) => h1.send_request(method, path, extra_headers, body).await,
106 }
107 }
108
109 pub(crate) async fn send_request_streaming(
111 &mut self,
112 method: &str,
113 path: &str,
114 extra_headers: &[(&str, &str)],
115 body: Option<&[u8]>,
116 ) -> Result<StreamingResponse<'_>, HttpError> {
117 match &mut self.inner {
118 ConnectionInner::H2(h2) => {
119 let stream = h2
120 .send_request_streaming(method, path, &self.host, extra_headers, body)
121 .await?;
122 Ok(StreamingResponse::H2(stream))
123 }
124 ConnectionInner::H1(h1) => {
125 let stream = h1
126 .send_request_streaming(method, path, extra_headers, body)
127 .await?;
128 Ok(StreamingResponse::H1(stream))
129 }
130 }
131 }
132
133 pub fn close(&self) {
135 match &self.inner {
136 ConnectionInner::H2(h2) => h2.close(),
137 ConnectionInner::H1(h1) => h1.close(),
138 }
139 }
140
141 pub fn peer_will_close(&self) -> bool {
147 match &self.inner {
148 ConnectionInner::H2(h2) => h2.peer_will_close(),
149 ConnectionInner::H1(h1) => h1.peer_will_close(),
150 }
151 }
152}