1use super::{Body, Conn, Transport, TypeSet};
2use crate::{ClientHandler, ConnExt, Error, Result, Version};
3use smallvec::SmallVec;
4#[cfg(feature = "hickory")]
5use std::net::IpAddr;
6use std::{
7 borrow::Cow,
8 fmt::{self, Debug, Formatter},
9 future::{Future, IntoFuture},
10 mem,
11 net::SocketAddr,
12 pin::Pin,
13};
14use trillium_http::{ProtocolSession, Upgrade};
15use trillium_server_common::Destination;
16
17#[cfg(any(feature = "serde_json", feature = "sonic-rs"))]
21#[derive(thiserror::Error, Debug)]
22pub enum ClientSerdeError {
23 #[error(transparent)]
25 HttpError(#[from] Error),
26
27 #[cfg(feature = "sonic-rs")]
28 #[error(transparent)]
30 JsonError(#[from] sonic_rs::Error),
31
32 #[cfg(feature = "serde_json")]
33 #[error(transparent)]
35 JsonError(#[from] serde_json::Error),
36}
37
38impl Conn {
39 pub(crate) async fn exec(&mut self) -> Result<()> {
40 if let Some(error) = self.error.take() {
44 return Err(error);
45 }
46
47 let handler = self.client.arc_handler().clone();
49 handler.run(self).await?;
50
51 if !self.halted {
52 if let Err(e) = self.exec_network().await {
55 self.error = Some(e);
56 }
57 } else {
58 log::trace!("conn is halted, skipping network round-trip");
59 self.request_body = None;
64 }
65
66 handler.after_response(self).await?;
68
69 if let Some(e) = self.error.take() {
70 Err(e)
71 } else {
72 Ok(())
73 }
74 }
75
76 async fn exec_network(&mut self) -> Result<()> {
77 if self.http_version == Some(Version::Http0_9) {
78 return Err(Error::UnsupportedVersion(Version::Http0_9));
79 }
80
81 if self.try_reuse_h3_pool().await? {
87 return Ok(());
88 }
89 if self.try_exec_h2_pooled().await? {
90 return Ok(());
91 }
92
93 if self.try_establish_h3().await? {
96 return Ok(());
97 }
98
99 if self.http_version == Some(Version::Http2) {
103 return self.exec_h2_prior_knowledge().await;
104 }
105
106 self.exec_h1_or_promote_h2().await
107 }
108
109 pub(crate) fn body_len(&self) -> Option<u64> {
110 if let Some(ref body) = self.request_body {
111 body.len()
112 } else {
113 Some(0)
114 }
115 }
116
117 pub(crate) fn finalize_headers(&mut self) -> Result<()> {
118 match self.http_version() {
119 Version::Http1_0 | Version::Http1_1 => self.finalize_headers_h1(),
120 Version::Http2 => self.finalize_headers_h2(),
121 Version::Http3 if self.client.h3().is_some() => self.finalize_headers_h3(),
122 other => Err(Error::UnsupportedVersion(other)),
123 }
124 }
125
126 pub(crate) async fn origin_destination(&self) -> Result<Destination> {
135 let mut destination = Destination::from_url(&self.url)?;
136 let addrs = self.origin_socket_addrs().await?;
137 if !addrs.is_empty() {
138 destination.set_addrs(addrs);
139 }
140 match self.http_version {
141 Some(Version::Http1_0 | Version::Http1_1) => {
142 destination.set_alpn([Cow::Borrowed(b"http/1.1".as_slice())]);
143 }
144 Some(Version::Http2) => {
145 destination.set_alpn([Cow::Borrowed(b"h2".as_slice())]);
146 }
147 _ => {}
148 }
149 Ok(destination)
150 }
151
152 pub(crate) async fn origin_socket_addrs(&self) -> Result<SmallVec<[SocketAddr; 4]>> {
156 let Some(host) = self.url.host_str() else {
157 return Ok(SmallVec::new());
158 };
159 let port = self.url.port_or_known_default().unwrap_or(443);
160 self.resolve_socket_addrs(host, port).await
161 }
162}
163
164#[cfg(feature = "hickory")]
165impl Conn {
166 pub(crate) async fn resolve(
179 &self,
180 host: &str,
181 port: u16,
182 ) -> Result<Option<crate::dns::Resolved>> {
183 if host.parse::<IpAddr>().is_ok() {
184 return Ok(None);
185 }
186 match &self.client.resolver {
187 Some(resolver) => Ok(Some(
188 resolver
189 .resolve(&self.client, host, port, self.timeout)
190 .await?,
191 )),
192 None => Ok(None),
193 }
194 }
195
196 pub(crate) async fn resolve_socket_addrs(
197 &self,
198 host: &str,
199 port: u16,
200 ) -> Result<SmallVec<[SocketAddr; 4]>> {
201 Ok(self
202 .resolve(host, port)
203 .await?
204 .map(|resolved| resolved.socket_addrs(port))
205 .unwrap_or_default())
206 }
207}
208
209#[cfg(not(feature = "hickory"))]
210impl Conn {
211 pub(crate) async fn resolve_socket_addrs(
212 &self,
213 _host: &str,
214 _port: u16,
215 ) -> Result<SmallVec<[SocketAddr; 4]>> {
216 Ok(SmallVec::new())
217 }
218}
219
220impl Drop for Conn {
221 fn drop(&mut self) {
222 log::trace!("dropping client conn");
223 drop(self.take_response_body());
224 }
225}
226
227impl From<Conn> for Body {
228 fn from(mut conn: Conn) -> Body {
229 if let Some(body) = conn.body_override.take() {
232 return body;
233 }
234
235 match conn.take_received_body(true) {
236 Some(rb) => rb.into(),
237 None => Body::default(),
238 }
239 }
240}
241
242impl From<Conn> for Upgrade<Box<dyn Transport>> {
243 fn from(mut conn: Conn) -> Self {
252 let path = conn.path.take().unwrap_or_else(|| match conn.url.query() {
255 Some(q) => Cow::Owned(format!("{}?{q}", conn.url.path())),
256 None => Cow::Owned(conn.url.path().to_owned()),
257 });
258 let secure = conn.url.scheme() == "https";
259
260 Upgrade::from_parts(
261 mem::take(&mut conn.response_headers),
262 mem::take(&mut conn.request_headers),
263 path,
264 conn.method,
265 conn.transport
266 .take()
267 .expect("client conn has no transport — request not yet sent"),
268 mem::take(&mut conn.buffer),
269 mem::take(&mut conn.state),
270 conn.context.clone(),
271 None,
272 conn.authority.take(),
273 conn.scheme.take(),
274 mem::replace(&mut conn.protocol_session, ProtocolSession::Http1),
275 conn.protocol.take(),
276 conn.http_version(),
277 conn.status,
278 secure,
279 mem::take(&mut conn.response_body_state),
281 conn.response_trailers.take(),
284 )
285 }
286}
287
288impl IntoFuture for Conn {
289 type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send + 'static>>;
290 type Output = Result<Conn>;
291
292 fn into_future(mut self) -> Self::IntoFuture {
293 Box::pin(async move { (&mut self).await.map(|()| self) })
294 }
295}
296
297impl<'conn> IntoFuture for &'conn mut Conn {
298 type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send + 'conn>>;
299 type Output = Result<()>;
300
301 fn into_future(self) -> Self::IntoFuture {
302 Box::pin(async move {
303 loop {
306 let result = if let Some(duration) = self.timeout {
307 self.client
308 .connector()
309 .runtime()
310 .timeout(duration, self.exec())
311 .await
312 .unwrap_or(Err(Error::TimedOut("Conn", duration)))
313 } else {
314 self.exec().await
315 };
316
317 self.halted = false;
319
320 if let Err(e) = result {
321 self.followup = None;
324 return Err(e);
325 }
326
327 let Some(next) = self.take_followup() else {
328 break;
329 };
330
331 if let Some(body) = self.take_response_body() {
332 body.recycle().await;
333 }
334
335 let _displaced = mem::replace(self, next);
336 }
337 Ok(())
338 })
339 }
340}
341
342impl Debug for Conn {
343 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
344 f.debug_struct("Conn")
345 .field("authority", &self.authority)
346 .field("buffer", &String::from_utf8_lossy(&self.buffer))
347 .field("client", &self.client)
348 .field("protocol_session", &self.protocol_session)
349 .field("http_version", &self.http_version)
350 .field("method", &self.method)
351 .field("path", &self.path)
352 .field("request_body", &self.request_body)
353 .field("request_headers", &self.request_headers)
354 .field("request_target", &self.request_target)
355 .field("request_trailers", &self.request_trailers)
356 .field("response_body_state", &self.response_body_state)
357 .field("response_headers", &self.response_headers)
358 .field("response_trailers", &self.response_trailers)
359 .field("scheme", &self.scheme)
360 .field("state", &self.state)
361 .field("status", &self.status)
362 .field("url", &self.url)
363 .finish()
364 }
365}
366
367impl AsRef<TypeSet> for Conn {
368 fn as_ref(&self) -> &TypeSet {
369 &self.state
370 }
371}
372
373impl AsMut<TypeSet> for Conn {
374 fn as_mut(&mut self) -> &mut TypeSet {
375 &mut self.state
376 }
377}