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}