Skip to main content

rust_web_server/application/
mod.rs

1//! Application: the type a server runs for every request.
2//!
3//! An [`Application`] gets each parsed [`Request`](crate::request::Request) and its
4//! [`ConnectionInfo`](crate::server::ConnectionInfo) and returns a
5//! [`Response`](crate::response::Response) (or an error message). The server runs
6//! it on many threads, so it must be `Clone + Send + 'static`.
7//!
8//! The built-in [`App`](crate::app::App) is one: it starts from a `501` response
9//! with the default headers and walks a list of
10//! [`Controller`](crate::controller::Controller)s, each checking whether it
11//! matches and, if so, filling in the response. Most code uses `App`,
12//! [`Router`](crate::router::Router) or `App::with_state` instead of implementing
13//! this trait directly; see `src/application/example/` for a hand-written one.
14
15use crate::request::Request;
16use crate::response::Response;
17use crate::server::ConnectionInfo;
18
19#[cfg(test)]
20mod example;
21#[cfg(test)]
22mod tests;
23
24/// Dispatch trait that wires controllers into a request-handling loop.
25///
26/// Implement this to define which controllers run and in what order.
27/// Pass the implementation to [`Server::run`] or [`Server::run_tls`].
28///
29/// The built-in [`App`](crate::app::App) implementation covers static files,
30/// favicons, forms, and file uploads. Embed it or replace it entirely.
31pub trait Application {
32    /// Receives a parsed request and returns a fully-built response.
33    /// Walk your controller list with `is_matching` / `process` and return the first match.
34    fn execute(&self, request: &Request, connection: &ConnectionInfo) -> Result<Response, String>;
35
36    /// `true` when executing `request` is quick and never waits on anything
37    /// but the local filesystem — health checks, metrics, small static files.
38    /// The async servers (HTTP/1.1, HTTP/2, HTTP/3) then call [`execute`]
39    /// directly on the event loop, as nginx does, instead of handing the
40    /// request to tokio's blocking pool: that handoff (a shared lock and two
41    /// cross-thread wake-ups) costs more than serving a small file.
42    ///
43    /// Default `false`, and it must stay `false` for anything that can wait:
44    /// a database query, an upstream request, a lock held across I/O. Run on
45    /// the event loop, those would stall every other connection on that
46    /// worker. Wrappers answer `true` only when every layer agrees.
47    ///
48    /// [`execute`]: Application::execute
49    fn runs_inline(&self, _request: &Request, _connection: &ConnectionInfo) -> bool {
50        false
51    }
52
53    /// An asynchronous version of [`execute`] for this request, when the
54    /// application has one: the async servers await it on the connection's
55    /// task instead of tying up a blocking-pool thread while it waits (the
56    /// config-driven proxy uses this to wait for a backend without holding a
57    /// thread). `None` (the default) means "use `execute`". Wrappers return
58    /// `Some` only when they add no synchronous work of their own.
59    ///
60    /// [`execute`]: Application::execute
61    #[cfg(feature = "http2")]
62    fn execute_async<'a>(&'a self, _request: &'a Request, _connection: &'a ConnectionInfo) -> Option<AsyncResponse<'a>> {
63        None
64    }
65
66    /// `true` to receive this request's body as a stream ([`Body::Stream`])
67    /// instead of read into memory first: [`execute`] then runs while the
68    /// body is still arriving, on a blocking-pool thread, and reads it with
69    /// `std::io::Read` — a multi-gigabyte upload in a few chunks of memory.
70    /// Asked after the head is read, so `request.body` is empty here;
71    /// decide from the method, path and headers.
72    ///
73    /// Default `false`: the body is read first, as always. Async HTTP/1.1
74    /// and HTTP/2 honour it (HTTP/2 credits the stream's window back as the
75    /// handler reads); the HTTP/1.1-only build and HTTP/3 read the body
76    /// first regardless. Wrappers answer `true` only when every layer
77    /// leaves the body alone ([`Middleware::accepts_streamed_body`]).
78    ///
79    /// [`Body::Stream`]: crate::request::Body::Stream
80    /// [`execute`]: Application::execute
81    /// [`Middleware::accepts_streamed_body`]: crate::middleware::Middleware::accepts_streamed_body
82    fn streams_body(&self, _request: &Request, _connection: &ConnectionInfo) -> bool {
83        false
84    }
85}
86
87/// The future [`Application::execute_async`] returns.
88#[cfg(feature = "http2")]
89pub type AsyncResponse<'a> = std::pin::Pin<Box<dyn std::future::Future<Output = Result<Response, String>> + Send + 'a>>;