Skip to main content

trillium/
conn.rs

1use crate::{
2    Body, HeaderName, HeaderValues, Headers, Method, Status, Swansong, Transport, TypeSet, Version,
3    request_body::RequestBody,
4    transport::{box_transport, unbox_transport},
5    type_set::Entry,
6};
7use std::{
8    fmt::{self, Debug, Formatter},
9    future::Future,
10    net::IpAddr,
11    time::Instant,
12};
13
14/// # A Trillium HTTP connection.
15///
16/// A Conn represents both the request and response of a http connection,
17/// as well as any application state that is associated with that
18/// connection.
19///
20/// ## `with_{attribute}` naming convention
21///
22/// A convention that is used throughout trillium is that any interface
23/// that is named `with_{attribute}` will take ownership of the conn, set
24/// the attribute and return the conn, enabling chained calls like:
25///
26/// ```
27/// use trillium_testing::TestServer;
28///
29/// struct MyState(&'static str);
30/// async fn handler(mut conn: trillium::Conn) -> trillium::Conn {
31///     conn.with_response_header("content-type", "text/plain")
32///         .with_state(MyState("hello"))
33///         .with_body("hey there")
34///         .with_status(418)
35/// }
36///
37/// # trillium_testing::block_on(async {
38/// let app = TestServer::new(handler).await;
39/// app.get("/")
40///     .await
41///     .assert_status(418)
42///     .assert_body("hey there")
43///     .assert_header("content-type", "text/plain");
44/// # });
45/// ```
46///
47/// If you need to set a property on the conn without moving it,
48/// `set_{attribute}` associated functions will be your huckleberry, as is
49/// conventional in other rust projects.
50///
51/// ## State
52///
53/// Every trillium Conn contains a state type which is a set that contains at most one element for
54/// each type. State is the primary way that handlers attach data to a conn as it passes through a
55/// tuple handler. State access should generally be implemented by libraries using a private type
56/// and exposed with a `ConnExt` trait. See [library
57/// patterns](https://trillium.rs/library_patterns.html#state) for more elaboration and examples.
58///
59/// ## In relation to [`trillium_http::Conn`]
60///
61/// `trillium::Conn` is currently implemented as an abstraction on top of a
62/// [`trillium_http::Conn`]. In particular, `trillium::Conn` boxes the transport so that application
63/// code can be written without transport generics. See
64/// [`Transport`] for further reading on this.
65pub struct Conn {
66    pub(crate) inner: trillium_http::Conn<Box<dyn Transport>>,
67    halted: bool,
68    path: Vec<String>,
69}
70
71impl Debug for Conn {
72    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
73        f.debug_struct("Conn")
74            .field("inner", &self.inner)
75            .field("halted", &self.halted)
76            .field("path", &self.path)
77            .finish()
78    }
79}
80
81impl<T: Transport + 'static> From<trillium_http::Conn<T>> for Conn {
82    fn from(inner: trillium_http::Conn<T>) -> Self {
83        Self {
84            inner: inner.map_transport(box_transport),
85            halted: false,
86            path: vec![],
87        }
88    }
89}
90
91impl Conn {
92    /// `Conn::ok` is a convenience function for the common pattern of
93    /// setting a body and a 200 status in one call. It is exactly
94    /// identical to `conn.with_status(200).with_body(body).halt()`
95    ///
96    /// See [`Body::new_streaming`] and [`Body::new_with_trailers`] to construct a body from an
97    /// [`AsyncRead`](futures_lite::AsyncRead) or [`BodySource`](crate::BodySource)
98    ///
99    /// ```
100    /// use trillium::Conn;
101    /// use trillium_testing::TestServer;
102    ///
103    /// # trillium_testing::block_on(async {
104    /// let handler = |conn: Conn| async move { conn.ok("hello") };
105    /// let app = TestServer::new(handler).await;
106    /// app.get("/").await.assert_ok().assert_body("hello");
107    /// # });
108    /// ```
109    #[must_use]
110    pub fn ok(self, body: impl Into<Body>) -> Self {
111        self.with_status(200).with_body(body).halt()
112    }
113
114    /// returns the response status for this `Conn`, if it has been set.
115    /// ```
116    /// use trillium::Conn;
117    /// use trillium_testing::TestServer;
118    ///
119    /// # trillium_testing::block_on(async {
120    /// let handler = |mut conn: Conn| async move {
121    ///     assert!(conn.status().is_none());
122    ///     conn.set_status(200);
123    ///     assert_eq!(conn.status().unwrap(), trillium_http::Status::Ok);
124    ///     conn.ok("pass")
125    /// };
126    /// let app = TestServer::new(handler).await;
127    /// app.get("/").await.assert_ok();
128    /// # });
129    /// ```
130    pub fn status(&self) -> Option<Status> {
131        self.inner.status()
132    }
133
134    /// assigns a status to this response. see [`Conn::status`] for example usage
135    pub fn set_status(&mut self, status: impl TryInto<Status>) -> &mut Self {
136        self.inner.set_status(status);
137        self
138    }
139
140    /// sets the response status for this `Conn` and returns it. note that
141    /// this does not set the halted status.
142    ///
143    /// ```
144    /// use trillium::Conn;
145    /// use trillium_testing::TestServer;
146    ///
147    /// # trillium_testing::block_on(async {
148    /// let handler = |conn: Conn| async move { conn.with_status(418) };
149    /// let app = TestServer::new(handler).await;
150    /// app.get("/").await.assert_status(418);
151    /// # });
152    /// ```
153    #[must_use]
154    pub fn with_status(mut self, status: impl TryInto<Status>) -> Self {
155        self.set_status(status);
156        self
157    }
158
159    /// Sets the response body from any `impl Into<Body>` and returns the
160    /// `Conn` for fluent chaining. Note that this does not set the response
161    /// status or halted. See [`Conn::ok`] for a function that does both
162    /// of those.
163    ///
164    /// See [`Body::new_streaming`] and [`Body::new_with_trailers`] to construct a body from an
165    /// [`AsyncRead`](futures_lite::AsyncRead) or [`BodySource`](crate::BodySource)
166    ///
167    /// ```
168    /// use trillium::Conn;
169    /// use trillium_testing::TestServer;
170    ///
171    /// # trillium_testing::block_on(async {
172    /// let handler = |conn: Conn| async move { conn.with_body("hello") };
173    /// let app = TestServer::new(handler).await;
174    /// app.get("/").await.assert_body_contains("hello");
175    /// # });
176    /// ```
177    #[must_use]
178    pub fn with_body(mut self, body: impl Into<Body>) -> Self {
179        self.set_body(body);
180        self
181    }
182
183    /// Sets the response body from any `impl Into<Body>`. Note that this does not set the response
184    /// status or halted.
185    ///
186    /// See [`Body::new_streaming`] and [`Body::new_with_trailers`] to construct a body from an
187    /// [`AsyncRead`](futures_lite::AsyncRead) or [`BodySource`](crate::BodySource)
188    ///
189    /// ```
190    /// use trillium::Conn;
191    /// use trillium_testing::TestServer;
192    ///
193    /// # trillium_testing::block_on(async {
194    /// let handler = |mut conn: Conn| async move {
195    ///     conn.set_body("hello");
196    ///     assert_eq!(conn.response_len(), Some(5));
197    ///     conn.ok("pass")
198    /// };
199    /// let app = TestServer::new(handler).await;
200    /// app.get("/").await.assert_ok();
201    /// # });
202    /// ```
203    pub fn set_body(&mut self, body: impl Into<Body>) -> &mut Self {
204        self.inner.set_response_body(body);
205        self
206    }
207
208    /// Removes the response body from the `Conn`
209    ///
210    /// ```
211    /// use trillium::Conn;
212    /// use trillium_testing::TestServer;
213    ///
214    /// # trillium_testing::block_on(async {
215    /// let handler = |mut conn: Conn| async move {
216    ///     conn.set_body("hello");
217    ///     let body = conn.take_response_body().unwrap();
218    ///     assert_eq!(body.len(), Some(5));
219    ///     assert_eq!(conn.response_len(), None);
220    ///     conn.ok("pass")
221    /// };
222    /// let app = TestServer::new(handler).await;
223    /// app.get("/").await.assert_ok();
224    /// # });
225    /// ```
226    pub fn take_response_body(&mut self) -> Option<Body> {
227        self.inner.take_response_body()
228    }
229
230    /// Borrows the response body from the `Conn`
231    ///
232    /// ```
233    /// use trillium::Conn;
234    /// use trillium_testing::TestServer;
235    ///
236    /// # trillium_testing::block_on(async {
237    /// let handler = |mut conn: Conn| async move {
238    ///     conn.set_body("hello");
239    ///     let body = conn.response_body().unwrap();
240    ///     assert_eq!(body.len(), Some(5));
241    ///     assert!(body.is_static());
242    ///     assert_eq!(body.static_bytes(), Some(&b"hello"[..]));
243    ///     conn.ok("pass")
244    /// };
245    /// let app = TestServer::new(handler).await;
246    /// app.get("/").await.assert_ok();
247    /// # });
248    /// ```
249    pub fn response_body(&self) -> Option<&Body> {
250        self.inner.response_body()
251    }
252
253    /// Attempts to retrieve a &T from the state set
254    ///
255    /// ```
256    /// use trillium::Conn;
257    /// use trillium_testing::TestServer;
258    ///
259    /// struct Hello;
260    /// # trillium_testing::block_on(async {
261    /// let handler = |mut conn: Conn| async move {
262    ///     assert!(conn.state::<Hello>().is_none());
263    ///     conn.insert_state(Hello);
264    ///     assert!(conn.state::<Hello>().is_some());
265    ///     conn.ok("pass")
266    /// };
267    /// let app = TestServer::new(handler).await;
268    /// app.get("/").await.assert_ok();
269    /// # });
270    /// ```
271    pub fn state<T: Send + Sync + 'static>(&self) -> Option<&T> {
272        self.inner.state().get()
273    }
274
275    /// Attempts to retrieve a &mut T from the state set
276    pub fn state_mut<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
277        self.inner.state_mut().get_mut()
278    }
279
280    /// Inserts a new type into the state set. See [`Conn::state`]
281    /// for an example.
282    ///
283    /// Returns the previously-set instance of this type, if
284    /// any
285    pub fn insert_state<T: Send + Sync + 'static>(&mut self, state: T) -> Option<T> {
286        self.inner.state_mut().insert(state)
287    }
288
289    /// Puts a new type into the state set and returns the
290    /// `Conn`. this is useful for fluent chaining
291    #[must_use]
292    pub fn with_state<T: Send + Sync + 'static>(mut self, state: T) -> Self {
293        self.insert_state(state);
294        self
295    }
296
297    /// Removes a type from the state set and returns it, if present
298    pub fn take_state<T: Send + Sync + 'static>(&mut self) -> Option<T> {
299        self.inner.state_mut().take()
300    }
301
302    /// Returns an [`Entry`] for the state typeset that can be used with functions like
303    /// [`Entry::or_insert`], [`Entry::or_insert_with`], [`Entry::and_modify`], and others.
304    pub fn state_entry<T: Send + Sync + 'static>(&mut self) -> Entry<'_, T> {
305        self.inner.state_mut().entry()
306    }
307
308    /// Attempts to borrow a T from the immutable shared state set
309    pub fn shared_state<T: Send + Sync + 'static>(&self) -> Option<&T> {
310        self.inner.shared_state().get()
311    }
312
313    /// Returns a [`RequestBody`] that references this `Conn`. The `Conn`
314    /// retains all data and holds the singular transport, but the
315    /// [`RequestBody`] provides an interface to read body content.
316    ///
317    /// If the request included an `Expect: 100-continue` header, the 100 Continue response is sent
318    /// lazily on the first read from the returned [`RequestBody`].
319    ///
320    /// See also: [`Conn::request_body_string`] for a convenience function
321    /// when the content is expected to be utf8.
322    ///
323    /// # Examples
324    ///
325    /// ```
326    /// use trillium::Conn;
327    /// use trillium_testing::TestServer;
328    ///
329    /// # trillium_testing::block_on(async {
330    /// let handler = |mut conn: Conn| async move {
331    ///     let request_body = conn.request_body();
332    ///     assert_eq!(request_body.content_length(), Some(12));
333    ///     assert_eq!(request_body.read_string().await.unwrap(), "request body");
334    ///     conn.ok("pass")
335    /// };
336    /// let app = TestServer::new(handler).await;
337    /// app.post("/").with_body("request body").await.assert_ok();
338    /// # });
339    /// ```
340    pub fn request_body(&mut self) -> RequestBody<'_> {
341        self.inner.request_body().into()
342    }
343
344    /// Convenience function to read the content of a request body as a `String`.
345    ///
346    /// # Errors
347    ///
348    /// This will return an error variant if either there is an IO failure
349    /// on the underlying transport or if the body content is not a utf8
350    /// string.
351    ///
352    /// # Examples
353    ///
354    /// ```
355    /// use trillium::Conn;
356    /// use trillium_testing::TestServer;
357    ///
358    /// # trillium_testing::block_on(async {
359    /// let handler = |mut conn: Conn| async move {
360    ///     assert_eq!(conn.request_body_string().await.unwrap(), "request body");
361    ///     conn.ok("pass")
362    /// };
363    /// let app = TestServer::new(handler).await;
364    /// app.post("/").with_body("request body").await.assert_ok();
365    /// # });
366    /// ```
367    #[allow(clippy::missing_errors_doc)] // this is a false positive
368    pub async fn request_body_string(&mut self) -> trillium_http::Result<String> {
369        self.request_body().read_string().await
370    }
371
372    /// if there is a response body for this conn and it has a known
373    /// fixed length, it is returned from this function
374    ///
375    /// ```
376    /// use trillium::Conn;
377    /// use trillium_testing::TestServer;
378    ///
379    /// # trillium_testing::block_on(async {
380    /// let handler = |mut conn: Conn| async move {
381    ///     assert_eq!(conn.response_len(), None); // no body set yet
382    ///     conn.set_body("hello");
383    ///     assert_eq!(conn.response_len(), Some(5));
384    ///     conn.ok("pass")
385    /// };
386    /// let app = TestServer::new(handler).await;
387    /// app.get("/").await.assert_ok();
388    /// # });
389    /// ```
390    pub fn response_len(&self) -> Option<u64> {
391        self.inner.response_body().and_then(Body::len)
392    }
393
394    /// returns the request method for this conn.
395    /// ```
396    /// use trillium::Conn;
397    /// use trillium_http::Method;
398    /// use trillium_testing::TestServer;
399    ///
400    /// # trillium_testing::block_on(async {
401    /// let handler = |conn: Conn| async move {
402    ///     assert_eq!(conn.method(), Method::Get);
403    ///     conn.ok("pass")
404    /// };
405    /// let app = TestServer::new(handler).await;
406    /// app.get("/").await.assert_ok();
407    /// # });
408    /// ```
409    pub fn method(&self) -> Method {
410        self.inner.method()
411    }
412
413    /// Borrow the response headers
414    pub fn response_headers(&self) -> &Headers {
415        self.inner.response_headers()
416    }
417
418    /// Mutably borrow the response headers
419    pub fn response_headers_mut(&mut self) -> &mut Headers {
420        self.inner.response_headers_mut()
421    }
422
423    /// Borrow the request headers
424    pub fn request_headers(&self) -> &Headers {
425        self.inner.request_headers()
426    }
427
428    /// Mutably borrow request headers
429    pub fn request_headers_mut(&mut self) -> &mut Headers {
430        self.inner.request_headers_mut()
431    }
432
433    /// Borrow the request trailers, if any
434    ///
435    /// Trailers are only populated after reading a request body that includes trailers to
436    /// completion.
437    pub fn request_trailers(&self) -> Option<&Headers> {
438        self.inner.request_trailers()
439    }
440
441    /// Insert a header name and value/values into the response headers and return the conn.
442    ///
443    /// See also [`Headers::insert`] and [`Headers::append`]
444    ///
445    /// For a slight performance improvement, use a [`KnownHeaderName`](crate::KnownHeaderName) as
446    /// the first argument instead of a str.
447    #[must_use]
448    pub fn with_response_header(
449        mut self,
450        header_name: impl Into<HeaderName<'static>>,
451        header_value: impl Into<HeaderValues>,
452    ) -> Self {
453        self.insert_response_header(header_name, header_value);
454        self
455    }
456
457    /// Insert a header name and value/values into the response headers.
458    ///
459    /// See also [`Headers::insert`] and [`Headers::append`]
460    ///
461    /// For a slight performance improvement, use a [`KnownHeaderName`](crate::KnownHeaderName).
462    pub fn insert_response_header(
463        &mut self,
464        header_name: impl Into<HeaderName<'static>>,
465        header_value: impl Into<HeaderValues>,
466    ) {
467        self.response_headers_mut()
468            .insert(header_name, header_value);
469    }
470
471    /// returns the path for this request. note that this may not
472    /// represent the entire http request path if running nested
473    /// routers.
474    pub fn path(&self) -> &str {
475        self.path.last().map_or_else(|| self.inner.path(), |p| &**p)
476    }
477
478    /// returns query part of the request path
479    ///
480    /// ```
481    /// use trillium::Conn;
482    /// use trillium_testing::TestServer;
483    ///
484    /// # trillium_testing::block_on(async {
485    /// let handler = |conn: Conn| async move {
486    ///     let querystring = conn.querystring();
487    ///     if querystring == "c&d=e" {
488    ///         conn.ok("has query")
489    ///     } else {
490    ///         conn.ok("no query")
491    ///     }
492    /// };
493    /// let app = TestServer::new(handler).await;
494    /// app.get("/a/b?c&d=e").await.assert_body("has query");
495    /// app.get("/a/b").await.assert_body("no query");
496    /// # });
497    /// ```
498    ///
499    ///
500    /// # Parsing
501    ///
502    /// Trillium does not include a querystring parsing library, as there is no universal standard
503    /// for querystring encodings of arrays, but several library options exist, inluding:
504    ///
505    /// [`QueryStrong`](https://docs.rs/querystrong/) (by the author of trillium)
506    /// [`serde_qs`](https://docs.rs/serde_qs/)
507    /// [`querystring`](https://docs.rs/querystring/)
508    /// [`serde_querystring`](https://docs.rs/serde-querystring/latest/serde_querystring/)
509    pub fn querystring(&self) -> &str {
510        self.inner.querystring()
511    }
512
513    /// sets the `halted` attribute of this conn, preventing later
514    /// processing in a given tuple handler. returns
515    /// the conn for fluent chaining
516    ///
517    /// ```
518    /// use trillium::Conn;
519    /// use trillium_testing::TestServer;
520    ///
521    /// # trillium_testing::block_on(async {
522    /// let handler = |conn: Conn| async move { conn.halt() };
523    /// let app = TestServer::new(handler).await;
524    /// app.get("/").await.assert_status(404);
525    /// # });
526    /// ```
527    #[must_use]
528    pub const fn halt(mut self) -> Self {
529        self.set_halted(true);
530        self
531    }
532
533    /// sets the `halted` attribute of this conn. see [`Conn::halt`].
534    ///
535    /// ```
536    /// use trillium::Conn;
537    /// use trillium_testing::TestServer;
538    ///
539    /// # trillium_testing::block_on(async {
540    /// let handler = |mut conn: Conn| async move {
541    ///     assert!(!conn.is_halted());
542    ///     conn.set_halted(true);
543    ///     assert!(conn.is_halted());
544    ///     conn.ok("pass")
545    /// };
546    /// let app = TestServer::new(handler).await;
547    /// app.get("/").await.assert_ok();
548    /// # });
549    /// ```
550    pub const fn set_halted(&mut self, halted: bool) -> &mut Self {
551        self.halted = halted;
552        self
553    }
554
555    /// retrieves the halted state of this conn.  see [`Conn::halt`].
556    pub const fn is_halted(&self) -> bool {
557        self.halted
558    }
559
560    /// predicate function to indicate whether the connection is
561    /// secure. note that this does not necessarily indicate that the
562    /// transport itself is secure, as it may indicate that
563    /// `trillium_http` is behind a trusted reverse proxy that has
564    /// terminated tls and provided appropriate headers to indicate
565    /// this.
566    pub fn is_secure(&self) -> bool {
567        self.inner.is_secure()
568    }
569
570    /// The [`Instant`] that the first header bytes for this conn were
571    /// received, before any processing or parsing has been performed.
572    pub fn start_time(&self) -> Instant {
573        self.inner.start_time()
574    }
575
576    /// transforms this `trillium::Conn` into a `trillium_http::Conn`
577    /// with the specified transport type. Please note that this will
578    /// panic if you attempt to downcast from trillium's boxed
579    /// transport into the wrong transport type. Also note that this
580    /// is a lossy conversion, dropping the halted state and any
581    /// nested router path data.
582    ///
583    /// # Panics
584    ///
585    /// This will panic if you attempt to downcast to the wrong Transport type.
586    pub fn into_inner<T: Transport>(self) -> trillium_http::Conn<T> {
587        self.inner.map_transport(unbox_transport)
588    }
589
590    /// retrieves the remote ip address for this conn, if available.
591    pub fn peer_ip(&self) -> Option<IpAddr> {
592        self.inner.peer_ip()
593    }
594
595    /// sets the remote ip address for this conn.
596    pub fn set_peer_ip(&mut self, peer_ip: Option<IpAddr>) -> &mut Self {
597        self.inner.set_peer_ip(peer_ip);
598        self
599    }
600
601    /// for router implementations. pushes a route segment onto the path
602    ///
603    /// Pushing a path frame around a child handler call in [`Handler::run`][crate::Handler::run]
604    /// takes on a contract that extends beyond `run`: every other hook that dispatches to the
605    /// child by path must reproduce the same path context, or nested delegation will silently
606    /// misroute. Concretely, mirror the push/pop pair around the child call in
607    /// [`Handler::before_send`][crate::Handler::before_send], and use
608    /// [`Upgrade::push_path`][crate::Upgrade::push_path] /
609    /// [`Upgrade::pop_path`][crate::Upgrade::pop_path] when delegating in
610    /// [`Handler::has_upgrade`][crate::Handler::has_upgrade] and
611    /// [`Handler::upgrade`][crate::Handler::upgrade].
612    pub fn push_path(&mut self, path: String) {
613        self.path.push(path);
614    }
615
616    /// for router implementations. removes a route segment pushed by
617    /// [`push_path`][Conn::push_path]
618    pub fn pop_path(&mut self) {
619        self.path.pop();
620    }
621
622    /// Cancels and drops the future if the peer abandons this request
623    ///
624    /// If the client disconnects, this function will return None. If the future completes
625    /// without disconnection, this future will return Some containing the output of the future.
626    ///
627    /// See [`is_disconnected`][Self::is_disconnected] for how departure is detected on each
628    /// protocol. On HTTP/1.x, where detection is by reading, any bytes the client sends while
629    /// the future runs — an unread request body, or pipelined requests — are buffered, up to
630    /// 16kb. A client that fills that allowance is considered alive for the remainder of the
631    /// future, even if it disconnects afterwards. If the request has a body, read it before
632    /// calling this.
633    ///
634    /// Note that the inner future cannot borrow conn, so you will need to clone or take any
635    /// information needed to execute the future prior to executing this method.
636    ///
637    /// # Example
638    ///
639    /// ```rust
640    /// # use trillium::{Conn, Method};
641    /// async fn something_slow_and_cancel_safe() -> String {
642    ///     String::from("this was not actually slow")
643    /// }
644    /// async fn handler(mut conn: Conn) -> Conn {
645    ///     match conn
646    ///         .cancel_on_disconnect(async { something_slow_and_cancel_safe().await })
647    ///         .await
648    ///     {
649    ///         Some(returned_body) => conn.ok(returned_body),
650    ///         None => conn,
651    ///     }
652    /// }
653    /// ```
654    pub async fn cancel_on_disconnect<'a, Fut>(&'a mut self, fut: Fut) -> Option<Fut::Output>
655    where
656        Fut: Future + Send + 'a,
657    {
658        self.inner.cancel_on_disconnect(fut).await
659    }
660
661    /// Check whether the peer has abandoned this request.
662    ///
663    /// How departure becomes observable is protocol-specific. On HTTP/1.x this reads the
664    /// transport: any bytes the client sends — an unread request body, or pipelined requests —
665    /// are buffered, up to 16kb, and count as evidence of liveness. A client that fills that
666    /// allowance is reported as connected until the buffered bytes are read, so read the request
667    /// body before polling this in a long-running handler. On HTTP/2 this observes stream reset
668    /// and connection teardown, and on HTTP/3 stream cancellation and connection loss; neither
669    /// reads the transport, and neither treats the peer's half-close — which both protocols do
670    /// as a matter of course once the request is complete — as a departure.
671    ///
672    /// A client that vanishes without signalling is only reported once the transport notices,
673    /// which on HTTP/3 is QUIC's negotiated idle timeout and on HTTP/1.x and HTTP/2 depends on
674    /// the TCP configuration.
675    ///
676    /// # Example
677    ///
678    /// This is best to use at appropriate points in a long-running handler, like:
679    ///
680    /// ```rust
681    /// # use trillium::{Conn, Method};
682    /// # async fn something_slow_but_not_cancel_safe() {}
683    /// async fn handler(mut conn: Conn) -> Conn {
684    ///     for _ in 0..100 {
685    ///         if conn.is_disconnected().await {
686    ///             return conn;
687    ///         }
688    ///         something_slow_but_not_cancel_safe().await;
689    ///     }
690    ///     conn.ok("ok!")
691    /// }
692    /// ```
693    pub async fn is_disconnected(&mut self) -> bool {
694        self.inner.is_disconnected().await
695    }
696
697    /// Returns the http version over which this Conn is being communicated
698    pub fn http_version(&self) -> Version {
699        self.inner.http_version()
700    }
701
702    /// get the host for this conn, if it exists
703    pub fn host(&self) -> Option<&str> {
704        self.inner.host()
705    }
706
707    /// retrieves the combined path and any query
708    pub fn path_and_query(&self) -> &str {
709        self.inner.path_and_query()
710    }
711
712    /// retrieves a [`Swansong`] graceful shutdown controller
713    pub fn swansong(&self) -> Swansong {
714        self.inner.swansong()
715    }
716
717    #[doc(hidden)]
718    #[must_use]
719    pub fn upgrade(mut self) -> Self {
720        self.inner = self.inner.upgrade();
721        self
722    }
723}
724
725impl AsMut<trillium_http::Conn<Box<dyn Transport>>> for Conn {
726    fn as_mut(&mut self) -> &mut trillium_http::Conn<Box<dyn Transport>> {
727        &mut self.inner
728    }
729}
730
731impl AsRef<trillium_http::Conn<Box<dyn Transport>>> for Conn {
732    fn as_ref(&self) -> &trillium_http::Conn<Box<dyn Transport>> {
733        &self.inner
734    }
735}
736
737impl AsMut<TypeSet> for Conn {
738    fn as_mut(&mut self) -> &mut TypeSet {
739        self.inner.state_mut()
740    }
741}
742
743impl AsRef<TypeSet> for Conn {
744    fn as_ref(&self) -> &TypeSet {
745        self.inner.state()
746    }
747}
748
749#[cfg(test)]
750mod tests {
751    use super::Conn;
752
753    #[test]
754    fn conn_is_cheap_to_move() {
755        assert!(
756            size_of::<Conn>() <= 64,
757            "Conn is {} bytes",
758            size_of::<Conn>()
759        );
760    }
761}