rocket_community/
lib.rs

1#![recursion_limit = "256"]
2#![doc(html_root_url = "https://api.rocket.rs/master")]
3#![doc(html_favicon_url = "https://rocket.rs/images/favicon.ico")]
4#![doc(html_logo_url = "https://rocket.rs/images/logo-boxed.png")]
5#![cfg_attr(nightly, feature(doc_cfg))]
6#![cfg_attr(nightly, feature(decl_macro))]
7
8//! # Rocket - Core API Documentation
9//!
10//! Hello, and welcome to the core Rocket API documentation!
11//!
12//! This API documentation is highly technical and is purely a reference.
13//! There's an [overview] of Rocket on the main site as well as a [full,
14//! detailed guide]. If you'd like pointers on getting started, see the
15//! [quickstart] or [getting started] chapters of the guide.
16//!
17//! [overview]: https://rocket.rs/master/overview
18//! [full, detailed guide]: https://rocket.rs/master/guide
19//! [quickstart]: https://rocket.rs/master/guide/quickstart
20//! [getting started]: https://rocket.rs/master/guide/getting-started
21//!
22//! ## Usage
23//!
24//! Depend on `rocket` in `Cargo.toml`:
25//!
26//! ```toml
27//! [dependencies]
28//! rocket = { package = "rocket_community", version = "0.6.0" }
29//! ```
30//!
31//! (Note that this is a community fork of Rocket. The `package = "rocket_community"`
32//! configuration enables the documentation and example code to work as expected.)
33//!
34//! <small>Note that development versions, tagged with `-dev`, are not published
35//! and need to be specified as [git dependencies].</small>
36//!
37//! See the [guide](https://rocket.rs/master/guide) for more information on how
38//! to write Rocket applications. Here's a simple example to get you started:
39//!
40//! [git dependencies]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#specifying-dependencies-from-git-repositories
41//!
42//! ```rust,no_run
43//! #[macro_use] extern crate rocket_community as rocket;
44//!
45//! #[get("/")]
46//! fn hello() -> &'static str {
47//!     "Hello, world!"
48//! }
49//!
50//! #[launch]
51//! fn rocket() -> _ {
52//!     rocket::build().mount("/", routes![hello])
53//! }
54//! ```
55//!
56//! ## Features
57//!
58//! To avoid compiling unused dependencies, Rocket feature-gates optional
59//! functionality, some enabled by default:
60//!
61//! | Feature         | Default? | Description                                             |
62//! |-----------------|----------|---------------------------------------------------------|
63//! | `trace`         | Yes      | Enables the default Rocket tracing [subscriber].        |
64//! | `http2`         | Yes      | Support for HTTP/2 (enabled by default).                |
65//! | `secrets`       | No       | Support for authenticated, encrypted [private cookies]. |
66//! | `tls`           | No       | Support for [TLS] encrypted connections.                |
67//! | `mtls`          | No       | Support for verified clients via [mutual TLS].          |
68//! | `json`          | No       | Support for [JSON (de)serialization].                   |
69//! | `msgpack`       | No       | Support for [MessagePack (de)serialization].            |
70//! | `uuid`          | No       | Support for [UUID value parsing and (de)serialization]. |
71//! | `tokio-macros`  | No       | Enables the `macros` feature in the exported `tokio`    |
72//! | `http3-preview` | No       | Experimental preview support for [HTTP/3].              |
73//!
74//! Disabled features can be selectively enabled in `Cargo.toml`:
75//!
76//! ```toml
77//! [dependencies]
78//! rocket = { package = "rocket_community", version = "0.6.0", features = ["secrets", "tls", "json"] }
79//! ```
80//!
81//! Conversely, HTTP/2 can be disabled:
82//!
83//! ```toml
84//! [dependencies]
85//! rocket = { package = "rocket_community", version = "0.6.0", default-features = false }
86//! ```
87//!
88//! [subscriber]: crate::trace::subscriber
89//! [JSON (de)serialization]: crate::serde::json
90//! [MessagePack (de)serialization]: crate::serde::msgpack
91//! [UUID value parsing and (de)serialization]: crate::serde::uuid
92//! [private cookies]: https://rocket.rs/master/guide/requests/#private-cookies
93//! [TLS]: https://rocket.rs/master/guide/configuration/#tls
94//! [mutual TLS]: crate::mtls
95//! [HTTP/3]: crate::listener::quic
96//!
97//! ## Configuration
98//!
99//! Rocket offers a rich, extensible configuration system built on [Figment]. By
100//! default, Rocket applications are configured via a `Rocket.toml` file
101//! and/or `ROCKET_{PARAM}` environment variables, but applications may
102//! configure their own sources. See the [configuration guide] for full details.
103//!
104//! ## Testing
105//!
106//! The [`local`] module contains structures that facilitate unit and
107//! integration testing of a Rocket application. The top-level [`local`] module
108//! documentation and the [testing guide] include detailed examples.
109//!
110//! [configuration guide]: https://rocket.rs/master/guide/configuration/
111//! [testing guide]: https://rocket.rs/master/guide/testing/#testing
112//! [Figment]: https://docs.rs/figment
113
114// Allows using Rocket's codegen in Rocket itself.
115extern crate self as rocket;
116
117#[doc(hidden)]
118pub use async_stream;
119pub use either;
120pub use figment;
121pub use futures;
122pub use time;
123pub use tokio;
124pub use tracing;
125/// These are public dependencies! Update docs if these are changed, especially
126/// figment's version number in docs.
127#[doc(hidden)]
128pub use yansi;
129
130#[macro_use]
131pub mod trace;
132#[macro_use]
133pub mod outcome;
134#[macro_use]
135pub mod data;
136pub mod catcher;
137pub mod config;
138pub mod error;
139pub mod fairing;
140pub mod form;
141pub mod fs;
142pub mod http;
143pub mod listener;
144pub mod local;
145#[cfg(feature = "mtls")]
146#[cfg_attr(nightly, doc(cfg(feature = "mtls")))]
147pub mod mtls;
148pub mod request;
149pub mod response;
150pub mod route;
151#[doc(hidden)]
152pub mod sentinel;
153pub mod serde;
154pub mod shield;
155pub mod shutdown;
156#[cfg(feature = "tls")]
157#[cfg_attr(nightly, doc(cfg(feature = "tls")))]
158pub mod tls;
159
160mod erased;
161mod lifecycle;
162mod phase;
163#[path = "rocket.rs"]
164mod rkt;
165mod router;
166mod server;
167mod state;
168mod util;
169
170#[doc(inline)]
171pub use rocket_codegen::*;
172
173#[doc(inline)]
174pub use crate::catcher::Catcher;
175#[doc(inline)]
176pub use crate::config::Config;
177#[doc(inline)]
178pub use crate::data::Data;
179#[doc(inline)]
180pub use crate::error::Error;
181#[doc(inline)]
182pub use crate::phase::{Build, Ignite, Orbit, Phase};
183#[doc(inline)]
184pub use crate::request::Request;
185#[doc(inline)]
186pub use crate::response::Response;
187#[doc(inline)]
188pub use crate::rkt::Rocket;
189#[doc(inline)]
190pub use crate::route::Route;
191#[doc(inline)]
192pub use crate::sentinel::{Sentinel, Sentry};
193#[doc(inline)]
194pub use crate::shutdown::Shutdown;
195#[doc(inline)]
196pub use crate::state::State;
197
198/// Retrofits support for `async fn` in trait impls and declarations.
199///
200/// Any trait declaration or trait `impl` decorated with `#[async_trait]` is
201/// retrofitted with support for `async fn`s:
202///
203/// ```rust
204/// # extern crate rocket_community as rocket;
205/// # use rocket::*;
206/// #[async_trait]
207/// trait MyAsyncTrait {
208///     async fn do_async_work();
209/// }
210///
211/// #[async_trait]
212/// impl MyAsyncTrait for () {
213///     async fn do_async_work() { /* .. */ }
214/// }
215/// ```
216///
217/// All `impl`s for a trait declared with `#[async_trait]` must themselves be
218/// decorated with `#[async_trait]`. Many of Rocket's traits, such as
219/// [`FromRequest`](crate::request::FromRequest) and
220/// [`Fairing`](crate::fairing::Fairing) are `async`. As such, implementations
221/// of said traits must be decorated with `#[async_trait]`. See the individual
222/// trait docs for trait-specific details.
223///
224/// For more details on `#[async_trait]`, see [`async_trait`](mod@async_trait).
225#[doc(inline)]
226pub use async_trait::async_trait;
227
228const WORKER_PREFIX: &str = "rocket-worker";
229
230/// Creates a [`Rocket`] instance with the default config provider: aliases
231/// [`Rocket::build()`].
232pub fn build() -> Rocket<Build> {
233    Rocket::build()
234}
235
236/// Creates a [`Rocket`] instance with a custom config provider: aliases
237/// [`Rocket::custom()`].
238pub fn custom<T: figment::Provider>(provider: T) -> Rocket<Build> {
239    Rocket::custom(provider)
240}
241
242/// WARNING: This is unstable! Do not use this method outside of Rocket!
243#[doc(hidden)]
244pub fn async_run<F, R>(fut: F, workers: usize, sync: usize, force_end: bool, name: &str) -> R
245where
246    F: std::future::Future<Output = R>,
247{
248    let runtime = tokio::runtime::Builder::new_multi_thread()
249        .thread_name(name)
250        .worker_threads(workers)
251        .max_blocking_threads(sync)
252        .enable_all()
253        .build()
254        .expect("create tokio runtime");
255
256    let result = runtime.block_on(fut);
257    if force_end {
258        runtime.shutdown_timeout(std::time::Duration::from_millis(500));
259    }
260
261    result
262}
263
264/// WARNING: This is unstable! Do not use this method outside of Rocket!
265#[doc(hidden)]
266pub fn async_test<R>(fut: impl std::future::Future<Output = R>) -> R {
267    async_run(fut, 1, 32, true, &format!("{WORKER_PREFIX}-test-thread"))
268}
269
270/// WARNING: This is unstable! Do not use this method outside of Rocket!
271#[doc(hidden)]
272pub fn async_main<R>(fut: impl std::future::Future<Output = R> + Send) -> R {
273    fn bail<T, E: crate::trace::Trace>(e: E) -> T {
274        e.trace_error();
275        panic!("aborting due to error")
276    }
277
278    // FIXME: We need to run `fut` to get the user's `Figment` to properly set
279    // up the async env, but we need the async env to run `fut`. So we're stuck.
280    // Tokio doesn't let us take the state from one async env and migrate it to
281    // another, so we need to use one, making this impossible.
282    //
283    // So as a result, we only use values from Rocket's figment. These
284    // values won't reflect swaps of `Rocket` in attach fairings with different
285    // config values, or values from non-Rocket configs. See tokio-rs/tokio#3329
286    // for a necessary resolution in `tokio`.
287    let fig = Config::figment();
288    let workers = fig.extract_inner(Config::WORKERS).unwrap_or_else(bail);
289    let max_blocking = fig.extract_inner(Config::MAX_BLOCKING).unwrap_or_else(bail);
290    let force = fig
291        .focus(Config::SHUTDOWN)
292        .extract_inner("force")
293        .unwrap_or_else(bail);
294    async_run(
295        fut,
296        workers,
297        max_blocking,
298        force,
299        &format!("{WORKER_PREFIX}-thread"),
300    )
301}
302
303/// Executes a `future` to completion on a new tokio-based Rocket async runtime.
304///
305/// The runtime is terminated on shutdown, and the future's resolved value is
306/// returned.
307///
308/// # Considerations
309///
310/// This function is a low-level mechanism intended to be used to execute the
311/// future returned by [`Rocket::launch()`] in a self-contained async runtime
312/// designed for Rocket. It runs futures in exactly the same manner as
313/// [`#[launch]`](crate::launch) and [`#[main]`](crate::main) do and is thus
314/// _never_ the preferred mechanism for running a Rocket application. _Always_
315/// prefer to use the [`#[launch]`](crate::launch) or [`#[main]`](crate::main)
316/// attributes. For example [`#[main]`](crate::main) can be used even when
317/// Rocket is just a small part of a bigger application:
318///
319/// ```rust,no_run
320/// # extern crate rocket_community as rocket;
321/// #[rocket::main]
322/// async fn main() {
323///     # let should_start_server_in_foreground = false;
324///     # let should_start_server_in_background = false;
325///     let rocket = rocket::build();
326///     if should_start_server_in_foreground {
327///         rocket::build().launch().await;
328///     } else if should_start_server_in_background {
329///         rocket::tokio::spawn(rocket.launch());
330///     } else {
331///         // do something else
332///     }
333/// }
334/// ```
335///
336/// See [Rocket#launching] for more on using these attributes.
337///
338/// # Example
339///
340/// Build an instance of Rocket, launch it, and wait for shutdown:
341///
342/// ```rust,no_run
343/// # extern crate rocket_community as rocket;
344/// use rocket::fairing::AdHoc;
345///
346/// let rocket = rocket::build()
347///     .attach(AdHoc::on_liftoff("Liftoff Printer", |_| Box::pin(async move {
348///         println!("Stalling liftoff for a second...");
349///         rocket::tokio::time::sleep(std::time::Duration::from_secs(1)).await;
350///         println!("And we're off!");
351///     })));
352///
353/// rocket::execute(rocket.launch());
354/// ```
355///
356/// Launch a pre-built instance of Rocket and wait for it to shutdown:
357///
358/// ```rust,no_run
359/// # extern crate rocket_community as rocket;
360/// use rocket::{Rocket, Ignite, Phase, Error};
361///
362/// fn launch<P: Phase>(rocket: Rocket<P>) -> Result<Rocket<Ignite>, Error> {
363///     rocket::execute(rocket.launch())
364/// }
365/// ```
366///
367/// Do async work to build an instance of Rocket, launch, and wait for shutdown:
368///
369/// ```rust,no_run
370/// # extern crate rocket_community as rocket;
371/// use rocket::fairing::AdHoc;
372///
373/// // This line can also be inside of the `async` block.
374/// let rocket = rocket::build();
375///
376/// rocket::execute(async move {
377///     let rocket = rocket.ignite().await?;
378///     let config = rocket.config();
379///     rocket.launch().await
380/// });
381/// ```
382pub fn execute<R, F>(future: F) -> R
383where
384    F: std::future::Future<Output = R> + Send,
385{
386    async_main(future)
387}
388
389/// Returns a future that evaluates to `true` exactly when there is a presently
390/// running tokio async runtime that was likely started by Rocket.
391fn running_within_rocket_async_rt() -> impl std::future::Future<Output = bool> {
392    use futures::FutureExt;
393
394    tokio::task::spawn_blocking(|| {
395        let this = std::thread::current();
396        this.name().is_some_and(|s| s.starts_with(WORKER_PREFIX))
397    })
398    .map(|r| r.unwrap_or(false))
399}