trillium_http/http_context.rs
1use crate::{
2 Conn, ConnectionStatus, HttpConfig, Result, TypeSet, Upgrade, headers::qpack::HeaderObserver,
3};
4use fieldwork::Fieldwork;
5use futures_lite::{AsyncRead, AsyncWrite};
6use std::{future::Future, sync::Arc};
7use swansong::{ShutdownCompletion, Swansong};
8/// This struct represents the shared configuration and context for a http server.
9///
10/// This currently contains tunable parameters in a [`HttpConfig`], the [`Swansong`] graceful
11/// shutdown control interface, and a shared [`TypeSet`] that contains application-specific
12/// information about the running server
13#[derive(Default, Debug, Fieldwork)]
14#[fieldwork(get, set, get_mut, with)]
15pub struct HttpContext {
16 /// [`HttpConfig`] performance and security parameters
17 pub(crate) config: HttpConfig,
18
19 /// [`Swansong`] graceful shutdown interface
20 pub(crate) swansong: Swansong,
21
22 /// [`TypeSet`] shared state
23 pub(crate) shared_state: TypeSet,
24
25 /// Per-listener QPACK header-frequency observer. Shared by `Arc` across all connections
26 /// a given listener accepts; runtime adapters isolate it per hop-and-direction via
27 /// [`__isolate_qpack_observer`](Self::__isolate_qpack_observer).
28 #[cfg_attr(not(feature = "unstable"), field = false)]
29 pub(crate) observer: Arc<HeaderObserver>,
30}
31impl AsRef<TypeSet> for HttpContext {
32 fn as_ref(&self) -> &TypeSet {
33 &self.shared_state
34 }
35}
36
37impl AsMut<TypeSet> for HttpContext {
38 fn as_mut(&mut self) -> &mut TypeSet {
39 &mut self.shared_state
40 }
41}
42
43impl AsRef<Swansong> for HttpContext {
44 fn as_ref(&self) -> &Swansong {
45 &self.swansong
46 }
47}
48
49impl AsRef<HttpConfig> for HttpContext {
50 fn as_ref(&self) -> &HttpConfig {
51 &self.config
52 }
53}
54
55impl HttpContext {
56 /// Construct a new `HttpContext`
57 pub fn new() -> Self {
58 Self::default()
59 }
60
61 /// Perform HTTP on the provided transport, applying the provided `async Conn -> Conn` handler
62 /// function for every distinct http request-response.
63 ///
64 /// For any given invocation of `HttpContext::run`, the handler function may run any number of
65 /// times, depending on whether the connection is reused by the client.
66 ///
67 /// This can only be called on an `Arc<HttpContext>` because an arc clone is moved into the
68 /// Conn.
69 ///
70 /// # Errors
71 ///
72 /// This function will return an [`Error`](crate::Error) if any of the http requests is
73 /// irrecoverably malformed or otherwise noncompliant.
74 pub async fn run<Transport, Handler, Fut>(
75 self: Arc<Self>,
76 transport: Transport,
77 mut handler: Handler,
78 ) -> Result<Option<Upgrade<Transport>>>
79 where
80 Transport: AsyncRead + AsyncWrite + Unpin + Send + Sync + 'static,
81 Handler: FnMut(Conn<Transport>) -> Fut,
82 Fut: Future<Output = Conn<Transport>>,
83 {
84 let _guard = self.swansong.guard();
85 let buffer = Vec::with_capacity(self.config.request_buffer_initial_len).into();
86
87 let mut conn = Conn::new_internal(self, transport, buffer).await?;
88
89 loop {
90 conn = match handler(conn).await.send().await? {
91 ConnectionStatus::Upgrade(upgrade) => return Ok(Some(upgrade)),
92 ConnectionStatus::Close => return Ok(None),
93 ConnectionStatus::Conn(next) => next,
94 }
95 }
96 }
97
98 /// Attempt graceful shutdown of this server.
99 ///
100 /// The returned [`ShutdownCompletion`] type can
101 /// either be awaited in an async context or blocked on with [`ShutdownCompletion::block`] in a
102 /// blocking context
103 pub fn shut_down(&self) -> ShutdownCompletion {
104 self.swansong.shut_down()
105 }
106
107 /// Replace this context's QPACK header observer with a fresh, empty one.
108 ///
109 /// Runtime adapters (trillium-server-common, trillium-client) call this during listener
110 /// setup so that each hop-and-direction pair in a deployment gets its own observer. A
111 /// reverse proxy's inbound server observer is distinct from its outbound client observer
112 /// by construction, so header values one hop forwards (e.g. `authorization`, `cookie`)
113 /// cannot reach the QPACK state of unrelated clients on the other hop.
114 ///
115 /// Not part of the stable public API; exposed only so adapter crates can call it.
116 #[doc(hidden)]
117 pub fn __isolate_qpack_observer(&mut self) -> &mut Self {
118 self.observer = Arc::new(HeaderObserver::default());
119 log::trace!(
120 target: "qpack_metrics",
121 "isolated fresh QPACK observer for this context (ptr={:p})",
122 Arc::as_ptr(&self.observer),
123 );
124 self
125 }
126}