Skip to main content

rust_web_server/application/
mod.rs

1use crate::request::Request;
2use crate::response::Response;
3use crate::server::ConnectionInfo;
4
5#[cfg(test)]
6mod example;
7#[cfg(test)]
8mod tests;
9
10/// Dispatch trait that wires controllers into a request-handling loop.
11///
12/// Implement this to define which controllers run and in what order.
13/// Pass the implementation to [`Server::run`] or [`Server::run_tls`].
14///
15/// The built-in [`App`](crate::app::App) implementation covers static files,
16/// favicons, forms, and file uploads. Embed it or replace it entirely.
17pub trait Application {
18    /// Receives a parsed request and returns a fully-built response.
19    /// Walk your controller list with `is_matching` / `process` and return the first match.
20    fn execute(&self, request: &Request, connection: &ConnectionInfo) -> Result<Response, String>;
21
22    /// `true` when executing `request` is quick and never waits on anything
23    /// but the local filesystem — health checks, metrics, small static files.
24    /// The async servers (HTTP/1.1, HTTP/2, HTTP/3) then call [`execute`]
25    /// directly on the event loop, as nginx does, instead of handing the
26    /// request to tokio's blocking pool: that handoff (a shared lock and two
27    /// cross-thread wake-ups) costs more than serving a small file.
28    ///
29    /// Default `false`, and it must stay `false` for anything that can wait:
30    /// a database query, an upstream request, a lock held across I/O. Run on
31    /// the event loop, those would stall every other connection on that
32    /// worker. Wrappers answer `true` only when every layer agrees.
33    ///
34    /// [`execute`]: Application::execute
35    fn runs_inline(&self, _request: &Request, _connection: &ConnectionInfo) -> bool {
36        false
37    }
38
39    /// An asynchronous version of [`execute`] for this request, when the
40    /// application has one: the async servers await it on the connection's
41    /// task instead of tying up a blocking-pool thread while it waits (the
42    /// config-driven proxy uses this to wait for a backend without holding a
43    /// thread). `None` (the default) means "use `execute`". Wrappers return
44    /// `Some` only when they add no synchronous work of their own.
45    ///
46    /// [`execute`]: Application::execute
47    #[cfg(feature = "http2")]
48    fn execute_async<'a>(&'a self, _request: &'a Request, _connection: &'a ConnectionInfo) -> Option<AsyncResponse<'a>> {
49        None
50    }
51}
52
53/// The future [`Application::execute_async`] returns.
54#[cfg(feature = "http2")]
55pub type AsyncResponse<'a> = std::pin::Pin<Box<dyn std::future::Future<Output = Result<Response, String>> + Send + 'a>>;