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 match self.exec_network_dispatch().await {
82 Err(Error::ExtendedConnectUnsupported)
88 if !self.strict_http_version && self.protocol.is_some() =>
89 {
90 log::debug!(
91 "peer does not support extended CONNECT; retrying as an HTTP/1.1 upgrade"
92 );
93 self.http_version = Some(Version::Http1_1);
94 self.headers_finalized = false;
95 self.exec_h1_or_promote_h2().await
96 }
97 other => other,
98 }
99 }
100
101 async fn exec_network_dispatch(&mut self) -> Result<()> {
102 if self.try_reuse_h3_pool().await? {
108 return Ok(());
109 }
110 if self.try_exec_h2_pooled().await? {
111 return Ok(());
112 }
113
114 if self.try_establish_h3().await? {
117 return Ok(());
118 }
119
120 if self.http_version == Some(Version::Http2) {
124 return self.exec_h2_prior_knowledge().await;
125 }
126
127 self.exec_h1_or_promote_h2().await
128 }
129
130 pub(crate) fn body_len(&self) -> Option<u64> {
131 if let Some(ref body) = self.request_body {
132 body.len()
133 } else {
134 Some(0)
135 }
136 }
137
138 pub(crate) fn finalize_headers(&mut self) -> Result<()> {
139 match self.http_version() {
140 Version::Http1_0 | Version::Http1_1 => self.finalize_headers_h1(),
141 Version::Http2 => self.finalize_headers_h2(),
142 Version::Http3 if self.client.h3().is_some() => self.finalize_headers_h3(),
143 other => Err(Error::UnsupportedVersion(other)),
144 }
145 }
146
147 pub(crate) async fn origin_destination(&self) -> Result<Destination> {
156 let mut destination = Destination::from_url(&self.url)?;
157 let addrs = self.origin_socket_addrs().await?;
158 if !addrs.is_empty() {
159 destination.set_addrs(addrs);
160 }
161 match self.http_version {
162 Some(Version::Http1_0 | Version::Http1_1) => {
163 destination.set_alpn([Cow::Borrowed(b"http/1.1".as_slice())]);
164 }
165 Some(Version::Http2) => {
166 destination.set_alpn([Cow::Borrowed(b"h2".as_slice())]);
167 }
168 _ => {}
169 }
170 Ok(destination)
171 }
172
173 pub(crate) async fn origin_socket_addrs(&self) -> Result<SmallVec<[SocketAddr; 4]>> {
177 let Some(host) = self.url.host_str() else {
178 return Ok(SmallVec::new());
179 };
180 let port = self.url.port_or_known_default().unwrap_or(443);
181 self.resolve_socket_addrs(host, port).await
182 }
183}
184
185#[cfg(feature = "hickory")]
186impl Conn {
187 pub(crate) async fn resolve(
200 &self,
201 host: &str,
202 port: u16,
203 ) -> Result<Option<crate::dns::Resolved>> {
204 if host.parse::<IpAddr>().is_ok() {
205 return Ok(None);
206 }
207 match &self.client.resolver {
208 Some(resolver) => Ok(Some(
209 resolver
210 .resolve(&self.client, host, port, self.timeout)
211 .await?,
212 )),
213 None => Ok(None),
214 }
215 }
216
217 pub(crate) async fn resolve_socket_addrs(
218 &self,
219 host: &str,
220 port: u16,
221 ) -> Result<SmallVec<[SocketAddr; 4]>> {
222 Ok(self
223 .resolve(host, port)
224 .await?
225 .map(|resolved| resolved.socket_addrs(port))
226 .unwrap_or_default())
227 }
228}
229
230#[cfg(not(feature = "hickory"))]
231impl Conn {
232 pub(crate) async fn resolve_socket_addrs(
233 &self,
234 _host: &str,
235 _port: u16,
236 ) -> Result<SmallVec<[SocketAddr; 4]>> {
237 Ok(SmallVec::new())
238 }
239}
240
241impl Drop for Conn {
242 fn drop(&mut self) {
243 log::trace!("dropping client conn");
244 drop(self.take_response_body());
245 }
246}
247
248impl From<Conn> for Body {
249 fn from(mut conn: Conn) -> Body {
250 if let Some(body) = conn.body_override.take() {
253 return body;
254 }
255
256 match conn.take_received_body(true) {
257 Some(rb) => rb.into(),
258 None => Body::default(),
259 }
260 }
261}
262
263impl From<Conn> for Upgrade<Box<dyn Transport>> {
264 fn from(mut conn: Conn) -> Self {
273 let path = conn.path.take().unwrap_or_else(|| match conn.url.query() {
276 Some(q) => Cow::Owned(format!("{}?{q}", conn.url.path())),
277 None => Cow::Owned(conn.url.path().to_owned()),
278 });
279 let secure = conn.url.scheme() == "https";
280
281 Upgrade::from_parts(
282 mem::take(&mut conn.response_headers),
283 mem::take(&mut conn.request_headers),
284 path,
285 conn.method,
286 conn.transport
287 .take()
288 .expect("client conn has no transport — request not yet sent"),
289 mem::take(&mut conn.buffer),
290 mem::take(&mut conn.state),
291 conn.context.clone(),
292 None,
293 conn.authority.take(),
294 conn.scheme.take(),
295 mem::replace(&mut conn.protocol_session, ProtocolSession::Http1),
296 conn.protocol.take(),
297 conn.http_version(),
298 conn.status,
299 secure,
300 mem::take(&mut conn.response_body_state),
302 conn.response_trailers.take(),
305 )
306 }
307}
308
309impl IntoFuture for Conn {
310 type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send + 'static>>;
311 type Output = Result<Conn>;
312
313 fn into_future(mut self) -> Self::IntoFuture {
314 Box::pin(async move { (&mut self).await.map(|()| self) })
315 }
316}
317
318impl<'conn> IntoFuture for &'conn mut Conn {
319 type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send + 'conn>>;
320 type Output = Result<()>;
321
322 fn into_future(self) -> Self::IntoFuture {
323 Box::pin(async move {
324 loop {
327 let result = if let Some(duration) = self.timeout {
328 self.client
329 .connector()
330 .runtime()
331 .timeout(duration, self.exec())
332 .await
333 .unwrap_or(Err(Error::TimedOut("Conn", duration)))
334 } else {
335 self.exec().await
336 };
337
338 self.halted = false;
340
341 if let Err(e) = result {
342 self.followup = None;
345 return Err(e);
346 }
347
348 let Some(next) = self.take_followup() else {
349 break;
350 };
351
352 if let Some(body) = self.take_response_body() {
353 body.recycle().await;
354 }
355
356 let _displaced = mem::replace(self, next);
357 }
358 Ok(())
359 })
360 }
361}
362
363impl Debug for Conn {
364 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
365 f.debug_struct("Conn")
366 .field("authority", &self.authority)
367 .field("buffer", &String::from_utf8_lossy(&self.buffer))
368 .field("client", &self.client)
369 .field("protocol_session", &self.protocol_session)
370 .field("http_version", &self.http_version)
371 .field("method", &self.method)
372 .field("path", &self.path)
373 .field("request_body", &self.request_body)
374 .field("request_headers", &self.request_headers)
375 .field("request_target", &self.request_target)
376 .field("request_trailers", &self.request_trailers)
377 .field("response_body_state", &self.response_body_state)
378 .field("response_headers", &self.response_headers)
379 .field("response_trailers", &self.response_trailers)
380 .field("scheme", &self.scheme)
381 .field("state", &self.state)
382 .field("status", &self.status)
383 .field("url", &self.url)
384 .finish()
385 }
386}
387
388impl AsRef<TypeSet> for Conn {
389 fn as_ref(&self) -> &TypeSet {
390 &self.state
391 }
392}
393
394impl AsMut<TypeSet> for Conn {
395 fn as_mut(&mut self) -> &mut TypeSet {
396 &mut self.state
397 }
398}