rocket/
rkt.rs

1use std::fmt;
2use std::ops::{Deref, DerefMut};
3use std::net::SocketAddr;
4
5use yansi::Paint;
6use either::Either;
7use figment::{Figment, Provider};
8
9use crate::{Catcher, Config, Route, Shutdown, sentinel, shield::Shield};
10use crate::router::Router;
11use crate::trip_wire::TripWire;
12use crate::fairing::{Fairing, Fairings};
13use crate::phase::{Phase, Build, Building, Ignite, Igniting, Orbit, Orbiting};
14use crate::phase::{Stateful, StateRef, State};
15use crate::http::uri::{self, Origin};
16use crate::http::ext::IntoOwned;
17use crate::error::{Error, ErrorKind};
18use crate::log::PaintExt;
19
20/// The application server itself.
21///
22/// # Phases
23///
24/// A `Rocket` instance represents a web server and its state. It progresses
25/// through three statically-enforced phases: build, ignite, orbit.
26///
27/// * **Build**: _application and server configuration_
28///
29///   This phase enables:
30///
31///     * setting configuration options
32///     * mounting/registering routes/catchers
33///     * managing state
34///     * attaching fairings
35///
36///   This is the _only_ phase in which an instance can be modified. To finalize
37///   changes, an instance is ignited via [`Rocket::ignite()`], progressing it
38///   into the _ignite_ phase, or directly launched into orbit with
39///   [`Rocket::launch()`] which progress the instance through ignite into
40///   orbit.
41///
42/// * **Ignite**: _verification and finalization of configuration_
43///
44///   An instance in the [`Ignite`] phase is in its final configuration,
45///   available via [`Rocket::config()`]. Barring user-supplied interior
46///   mutation, application state is guaranteed to remain unchanged beyond this
47///   point. An instance in the ignite phase can be launched into orbit to serve
48///   requests via [`Rocket::launch()`].
49///
50/// * **Orbit**: _a running web server_
51///
52///   An instance in the [`Orbit`] phase represents a _running_ application,
53///   actively serving requests.
54///
55/// # Launching
56///
57/// To launch a `Rocket` application, the suggested approach is to return an
58/// instance of `Rocket<Build>` from a function named `rocket` marked with the
59/// [`#[launch]`](crate::launch) attribute:
60///
61///   ```rust,no_run
62///   # use rocket::launch;
63///   #[launch]
64///   fn rocket() -> _ {
65///       rocket::build()
66///   }
67///   ```
68///
69/// This generates a `main` function with an `async` runtime that runs the
70/// returned `Rocket` instance.
71///
72/// * **Manual Launching**
73///
74///   To launch an instance of `Rocket`, it _must_ progress through all three
75///   phases. To progress into the ignite or launch phases, a tokio `async`
76///   runtime is required. The [`#[main]`](crate::main) attribute initializes a
77///   Rocket-specific tokio runtime and runs the attributed `async fn` inside of
78///   it:
79///
80///   ```rust,no_run
81///   #[rocket::main]
82///   async fn main() -> Result<(), rocket::Error> {
83///       let _rocket = rocket::build()
84///           .ignite().await?
85///           .launch().await?;
86///
87///       Ok(())
88///   }
89///   ```
90///
91///   Note that [`Rocket::launch()`] automatically progresses an instance of
92///   `Rocket` from any phase into orbit:
93///
94///   ```rust,no_run
95///   #[rocket::main]
96///   async fn main() -> Result<(), rocket::Error> {
97///       let _rocket = rocket::build().launch().await?;
98///       Ok(())
99///   }
100///   ```
101///
102///   For extreme and rare cases in which [`#[main]`](crate::main) imposes
103///   obstinate restrictions, use [`rocket::execute()`](crate::execute()) to
104///   execute Rocket's `launch()` future.
105///
106/// * **Automatic Launching**
107///
108///   Manually progressing an instance of Rocket though its phases is only
109///   necessary when either an instance's finalized state is to be inspected (in
110///   the _ignite_ phase) or the instance is expected to deorbit due to
111///   [`Rocket::shutdown()`]. In the more common case when neither is required,
112///   the [`#[launch]`](crate::launch) attribute can be used. When applied to a
113///   function that returns a `Rocket<Build>`, it automatically initializes an
114///   `async` runtime and launches the function's returned instance:
115///
116///   ```rust,no_run
117///   # use rocket::launch;
118///   use rocket::{Rocket, Build};
119///
120///   #[launch]
121///   fn rocket() -> Rocket<Build> {
122///       rocket::build()
123///   }
124///   ```
125///
126///   To avoid needing to import _any_ items in the common case, the `launch`
127///   attribute will infer a return type written as `_` as `Rocket<Build>`:
128///
129///   ```rust,no_run
130///   # use rocket::launch;
131///   #[launch]
132///   fn rocket() -> _ {
133///       rocket::build()
134///   }
135///   ```
136pub struct Rocket<P: Phase>(pub(crate) P::State);
137
138impl Rocket<Build> {
139    /// Create a new `Rocket` application using the default configuration
140    /// provider, [`Config::figment()`].
141    ///
142    /// This method is typically called through the
143    /// [`rocket::build()`](crate::build) alias.
144    ///
145    /// # Examples
146    ///
147    /// ```rust
148    /// # use rocket::launch;
149    /// #[launch]
150    /// fn rocket() -> _ {
151    ///     rocket::build()
152    /// }
153    /// ```
154    #[must_use]
155    #[inline(always)]
156    pub fn build() -> Self {
157        Rocket::custom(Config::figment())
158    }
159
160    /// Creates a new `Rocket` application using the supplied configuration
161    /// provider.
162    ///
163    /// This method is typically called through the
164    /// [`rocket::custom()`](crate::custom()) alias.
165    ///
166    /// # Example
167    ///
168    /// ```rust
169    /// # use rocket::launch;
170    /// use rocket::figment::{Figment, providers::{Toml, Env, Format}};
171    ///
172    /// #[launch]
173    /// fn rocket() -> _ {
174    ///     let figment = Figment::from(rocket::Config::default())
175    ///         .merge(Toml::file("MyApp.toml").nested())
176    ///         .merge(Env::prefixed("MY_APP_").global());
177    ///
178    ///     rocket::custom(figment)
179    /// }
180    /// ```
181    #[must_use]
182    pub fn custom<T: Provider>(provider: T) -> Self {
183        // We initialize the logger here so that logging from fairings and so on
184        // are visible; we use the final config to set a max log-level in ignite
185        crate::log::init_default();
186
187        let rocket: Rocket<Build> = Rocket(Building {
188            figment: Figment::from(provider),
189            ..Default::default()
190        });
191
192        rocket.attach(Shield::default())
193    }
194
195    /// Sets the configuration provider in `self` to `provider`.
196    ///
197    /// A [`Figment`] generated from the current `provider` can _always_ be
198    /// retrieved via [`Rocket::figment()`]. However, because the provider can
199    /// be changed at any point prior to ignition, a [`Config`] can only be
200    /// retrieved in the ignite or orbit phases, or by manually extracting one
201    /// from a particular figment.
202    ///
203    /// # Example
204    ///
205    /// ```rust
206    /// use rocket::Config;
207    /// # use std::net::Ipv4Addr;
208    /// # use std::path::{Path, PathBuf};
209    /// # type Result = std::result::Result<(), rocket::Error>;
210    ///
211    /// let config = Config {
212    ///     port: 7777,
213    ///     address: Ipv4Addr::new(18, 127, 0, 1).into(),
214    ///     temp_dir: "/tmp/config-example".into(),
215    ///     ..Config::debug_default()
216    /// };
217    ///
218    /// # let _: Result = rocket::async_test(async move {
219    /// let rocket = rocket::custom(&config).ignite().await?;
220    /// assert_eq!(rocket.config().port, 7777);
221    /// assert_eq!(rocket.config().address, Ipv4Addr::new(18, 127, 0, 1));
222    /// assert_eq!(rocket.config().temp_dir.relative(), Path::new("/tmp/config-example"));
223    ///
224    /// // Create a new figment which modifies _some_ keys the existing figment:
225    /// let figment = rocket.figment().clone()
226    ///     .merge((Config::PORT, 8888))
227    ///     .merge((Config::ADDRESS, "171.64.200.10"));
228    ///
229    /// let rocket = rocket::custom(&config)
230    ///     .configure(figment)
231    ///     .ignite().await?;
232    ///
233    /// assert_eq!(rocket.config().port, 8888);
234    /// assert_eq!(rocket.config().address, Ipv4Addr::new(171, 64, 200, 10));
235    /// assert_eq!(rocket.config().temp_dir.relative(), Path::new("/tmp/config-example"));
236    /// # Ok(())
237    /// # });
238    /// ```
239    #[must_use]
240    pub fn configure<T: Provider>(mut self, provider: T) -> Self {
241        self.figment = Figment::from(provider);
242        self
243    }
244
245    #[track_caller]
246    fn load<'a, B, T, F, M>(mut self, kind: &str, base: B, items: Vec<T>, m: M, f: F) -> Self
247        where B: TryInto<Origin<'a>> + Clone + fmt::Display,
248              B::Error: fmt::Display,
249              M: Fn(&Origin<'a>, T) -> Result<T, uri::Error<'static>>,
250              F: Fn(&mut Self, T),
251              T: Clone + fmt::Display,
252    {
253        let mut base = match base.clone().try_into() {
254            Ok(origin) => origin.into_owned(),
255            Err(e) => {
256                error!("invalid {} base: {}", kind, Paint::white(&base));
257                error_!("{}", e);
258                info_!("{} {}", "in".primary(), std::panic::Location::caller());
259                panic!("aborting due to {} base error", kind);
260            }
261        };
262
263        if base.query().is_some() {
264            warn!("query in {} base '{}' is ignored", kind, Paint::white(&base));
265            base.clear_query();
266        }
267
268        for unmounted_item in items {
269            let item = match m(&base, unmounted_item.clone()) {
270                Ok(item) => item,
271                Err(e) => {
272                    error!("malformed URI in {} {}", kind, unmounted_item);
273                    error_!("{}", e);
274                    info_!("{} {}", Paint::white("in"), std::panic::Location::caller());
275                    panic!("aborting due to invalid {} URI", kind);
276                }
277            };
278
279            f(&mut self, item)
280        }
281
282        self
283    }
284
285    /// Mounts all of the routes in the supplied vector at the given `base`
286    /// path. Mounting a route with path `path` at path `base` makes the route
287    /// available at `base/path`.
288    ///
289    /// # Panics
290    ///
291    /// Panics if either:
292    ///   * the `base` mount point is not a valid static path: a valid origin
293    ///     URI without dynamic parameters.
294    ///
295    ///   * any route's URI is not a valid origin URI.
296    ///
297    ///     **Note:** _This kind of panic is guaranteed not to occur if the routes
298    ///     were generated using Rocket's code generation._
299    ///
300    /// # Examples
301    ///
302    /// Use the `routes!` macro to mount routes created using the code
303    /// generation facilities. Requests to the `/hello/world` URI will be
304    /// dispatched to the `hi` route.
305    ///
306    /// ```rust,no_run
307    /// # #[macro_use] extern crate rocket;
308    /// #
309    /// #[get("/world")]
310    /// fn hi() -> &'static str {
311    ///     "Hello!"
312    /// }
313    ///
314    /// #[launch]
315    /// fn rocket() -> _ {
316    ///     rocket::build().mount("/hello", routes![hi])
317    /// }
318    /// ```
319    ///
320    /// Manually create a route named `hi` at path `"/world"` mounted at base
321    /// `"/hello"`. Requests to the `/hello/world` URI will be dispatched to the
322    /// `hi` route.
323    ///
324    /// ```rust
325    /// # #[macro_use] extern crate rocket;
326    /// use rocket::{Request, Route, Data, route};
327    /// use rocket::http::Method;
328    ///
329    /// fn hi<'r>(req: &'r Request, _: Data<'r>) -> route::BoxFuture<'r> {
330    ///     route::Outcome::from(req, "Hello!").pin()
331    /// }
332    ///
333    /// #[launch]
334    /// fn rocket() -> _ {
335    ///     let hi_route = Route::new(Method::Get, "/world", hi);
336    ///     rocket::build().mount("/hello", vec![hi_route])
337    /// }
338    /// ```
339    #[must_use]
340    #[track_caller]
341    pub fn mount<'a, B, R>(self, base: B, routes: R) -> Self
342        where B: TryInto<Origin<'a>> + Clone + fmt::Display,
343              B::Error: fmt::Display,
344              R: Into<Vec<Route>>
345    {
346        self.load("route", base, routes.into(),
347            |base, route| route.map_base(|old| format!("{}{}", base, old)),
348            |r, route| r.0.routes.push(route))
349    }
350
351    /// Registers all of the catchers in the supplied vector, scoped to `base`.
352    ///
353    /// # Panics
354    ///
355    /// Panics if `base` is not a valid static path: a valid origin URI without
356    /// dynamic parameters.
357    ///
358    /// # Examples
359    ///
360    /// ```rust,no_run
361    /// # #[macro_use] extern crate rocket;
362    /// use rocket::Request;
363    ///
364    /// #[catch(500)]
365    /// fn internal_error() -> &'static str {
366    ///     "Whoops! Looks like we messed up."
367    /// }
368    ///
369    /// #[catch(404)]
370    /// fn not_found(req: &Request) -> String {
371    ///     format!("I couldn't find '{}'. Try something else?", req.uri())
372    /// }
373    ///
374    /// #[launch]
375    /// fn rocket() -> _ {
376    ///     rocket::build().register("/", catchers![internal_error, not_found])
377    /// }
378    /// ```
379    #[must_use]
380    pub fn register<'a, B, C>(self, base: B, catchers: C) -> Self
381        where B: TryInto<Origin<'a>> + Clone + fmt::Display,
382              B::Error: fmt::Display,
383              C: Into<Vec<Catcher>>
384    {
385        self.load("catcher", base, catchers.into(),
386            |base, catcher| catcher.map_base(|old| format!("{}{}", base, old)),
387            |r, catcher| r.0.catchers.push(catcher))
388    }
389
390    /// Add `state` to the state managed by this instance of Rocket.
391    ///
392    /// This method can be called any number of times as long as each call
393    /// refers to a different `T`.
394    ///
395    /// Managed state can be retrieved by any request handler via the
396    /// [`State`](crate::State) request guard. In particular, if a value of type `T`
397    /// is managed by Rocket, adding `State<T>` to the list of arguments in a
398    /// request handler instructs Rocket to retrieve the managed value.
399    ///
400    /// # Panics
401    ///
402    /// Panics if state of type `T` is already being managed.
403    ///
404    /// # Example
405    ///
406    /// ```rust,no_run
407    /// # #[macro_use] extern crate rocket;
408    /// use rocket::State;
409    ///
410    /// struct MyInt(isize);
411    /// struct MyString(String);
412    ///
413    /// #[get("/int")]
414    /// fn int(state: &State<MyInt>) -> String {
415    ///     format!("The stateful int is: {}", state.0)
416    /// }
417    ///
418    /// #[get("/string")]
419    /// fn string(state: &State<MyString>) -> &str {
420    ///     &state.0
421    /// }
422    ///
423    /// #[launch]
424    /// fn rocket() -> _ {
425    ///     rocket::build()
426    ///         .manage(MyInt(10))
427    ///         .manage(MyString("Hello, managed state!".to_string()))
428    ///         .mount("/", routes![int, string])
429    /// }
430    /// ```
431    #[must_use]
432    pub fn manage<T>(self, state: T) -> Self
433        where T: Send + Sync + 'static
434    {
435        let type_name = std::any::type_name::<T>();
436        if !self.state.set(state) {
437            error!("state for type '{}' is already being managed", type_name);
438            panic!("aborting due to duplicated managed state");
439        }
440
441        self
442    }
443
444    /// Attaches a fairing to this instance of Rocket. No fairings are eagerly
445    /// executed; fairings are executed at their appropriate time.
446    ///
447    /// If the attached fairing is _fungible_ and a fairing of the same name
448    /// already exists, this fairing replaces it.
449    ///
450    /// # Example
451    ///
452    /// ```rust,no_run
453    /// # #[macro_use] extern crate rocket;
454    /// use rocket::Rocket;
455    /// use rocket::fairing::AdHoc;
456    ///
457    /// #[launch]
458    /// fn rocket() -> _ {
459    ///     rocket::build()
460    ///         .attach(AdHoc::on_liftoff("Liftoff Message", |_| Box::pin(async {
461    ///             println!("We have liftoff!");
462    ///         })))
463    /// }
464    /// ```
465    #[must_use]
466    pub fn attach<F: Fairing>(mut self, fairing: F) -> Self {
467        self.fairings.add(Box::new(fairing));
468        self
469    }
470
471    /// Returns a `Future` that transitions this instance of `Rocket` into the
472    /// _ignite_ phase.
473    ///
474    /// When `await`ed, the future runs all _ignite_ fairings in serial,
475    /// [attach](Rocket::attach()) order, and verifies that `self` represents a
476    /// valid instance of `Rocket` ready for launch. This means that:
477    ///
478    ///   * All ignite fairings succeeded.
479    ///   * A valid [`Config`] was extracted from [`Rocket::figment()`].
480    ///   * If `secrets` are enabled, the extracted `Config` contains a safe
481    ///     secret key.
482    ///   * There are no [`Route#collisions`] or [`Catcher#collisions`]
483    ///     collisions.
484    ///   * No [`Sentinel`](crate::Sentinel) triggered an abort.
485    ///
486    /// If any of these conditions fail to be met, a respective [`Error`] is
487    /// returned.
488    ///
489    /// [configured]: Rocket::figment()
490    ///
491    /// # Example
492    ///
493    /// ```rust
494    /// use rocket::fairing::AdHoc;
495    ///
496    /// #[rocket::main]
497    /// async fn main() -> Result<(), rocket::Error> {
498    ///     let rocket = rocket::build()
499    ///         # .configure(rocket::Config::debug_default())
500    ///         .attach(AdHoc::on_ignite("Manage State", |rocket| async move {
501    ///             rocket.manage(String::from("managed string"))
502    ///         }));
503    ///
504    ///     // No fairings are run until ignition occurs.
505    ///     assert!(rocket.state::<String>().is_none());
506    ///
507    ///     let rocket = rocket.ignite().await?;
508    ///     assert_eq!(rocket.state::<String>().unwrap(), "managed string");
509    ///
510    ///     Ok(())
511    /// }
512    /// ```
513    pub async fn ignite(mut self) -> Result<Rocket<Ignite>, Error> {
514        self = Fairings::handle_ignite(self).await;
515        self.fairings.audit().map_err(|f| ErrorKind::FailedFairings(f.to_vec()))?;
516
517        // Extract the configuration; initialize the logger.
518        #[allow(unused_mut)]
519        let mut config = Config::try_from(&self.figment).map_err(ErrorKind::Config)?;
520        crate::log::init(&config);
521
522        // Check for safely configured secrets.
523        #[cfg(feature = "secrets")]
524        if !config.secret_key.is_provided() {
525            if config.profile != Config::DEBUG_PROFILE {
526                return Err(Error::new(ErrorKind::InsecureSecretKey(config.profile.clone())));
527            }
528
529            if config.secret_key.is_zero() {
530                config.secret_key = crate::config::SecretKey::generate()
531                    .unwrap_or_else(crate::config::SecretKey::zero);
532            }
533        } else if config.known_secret_key_used() {
534            warn!("The configured `secret_key` is exposed and insecure.");
535            warn_!("The configured key is publicly published and thus insecure.");
536            warn_!("Try generating a new key with `head -c64 /dev/urandom | base64`.");
537        }
538
539        // Initialize the router; check for collisions.
540        let mut router = Router::new();
541        self.routes.clone().into_iter().for_each(|r| router.add_route(r));
542        self.catchers.clone().into_iter().for_each(|c| router.add_catcher(c));
543        router.finalize().map_err(ErrorKind::Collisions)?;
544
545        // Finally, freeze managed state.
546        self.state.freeze();
547
548        // Log everything we know: config, routes, catchers, fairings.
549        // TODO: Store/print managed state type names?
550        config.pretty_print(self.figment());
551        log_items("📬 ", "Routes", self.routes(), |r| &r.uri.base, |r| &r.uri);
552        log_items("🥅 ", "Catchers", self.catchers(), |c| &c.base, |c| &c.base);
553        self.fairings.pretty_print();
554
555        // Ignite the rocket.
556        let rocket: Rocket<Ignite> = Rocket(Igniting {
557            router, config,
558            shutdown: Shutdown(TripWire::new()),
559            figment: self.0.figment,
560            fairings: self.0.fairings,
561            state: self.0.state,
562        });
563
564        // Query the sentinels, abort if requested.
565        let sentinels = rocket.routes().flat_map(|r| r.sentinels.iter());
566        sentinel::query(sentinels, &rocket).map_err(ErrorKind::SentinelAborts)?;
567
568        Ok(rocket)
569    }
570}
571
572fn log_items<T, I, B, O>(e: &str, t: &str, items: I, base: B, origin: O)
573    where T: fmt::Display + Copy, I: Iterator<Item = T>,
574          B: Fn(&T) -> &Origin<'_>, O: Fn(&T) -> &Origin<'_>
575{
576    let mut items: Vec<_> = items.collect();
577    if !items.is_empty() {
578        launch_meta!("{}{}:", e.emoji(), t.magenta());
579    }
580
581    items.sort_by_key(|i| origin(i).path().as_str().chars().count());
582    items.sort_by_key(|i| origin(i).path().segments().len());
583    items.sort_by_key(|i| base(i).path().as_str().chars().count());
584    items.sort_by_key(|i| base(i).path().segments().len());
585    items.iter().for_each(|i| launch_meta_!("{}", i));
586}
587
588impl Rocket<Ignite> {
589    /// Returns the finalized, active configuration. This is guaranteed to
590    /// remain stable through ignition and into orbit.
591    ///
592    /// # Example
593    ///
594    /// ```rust,no_run
595    /// #[rocket::main]
596    /// async fn main() -> Result<(), rocket::Error> {
597    ///     let rocket = rocket::build().ignite().await?;
598    ///     let config = rocket.config();
599    ///     Ok(())
600    /// }
601    /// ```
602    pub fn config(&self) -> &Config {
603        &self.config
604    }
605
606    /// Returns a handle which can be used to trigger a shutdown and detect a
607    /// triggered shutdown.
608    ///
609    /// A completed graceful shutdown resolves the future returned by
610    /// [`Rocket::launch()`]. If [`Shutdown::notify()`] is called _before_ an
611    /// instance is launched, it will be immediately shutdown after liftoff. See
612    /// [`Shutdown`] and [`config::Shutdown`](crate::config::Shutdown) for
613    /// details on graceful shutdown.
614    ///
615    /// # Example
616    ///
617    /// ```rust,no_run
618    /// # use std::time::Duration;
619    /// use rocket::tokio::{self, time};
620    ///
621    /// #[rocket::main]
622    /// async fn main() -> Result<(), rocket::Error> {
623    ///     let rocket = rocket::build().ignite().await?;
624    ///
625    ///     let shutdown = rocket.shutdown();
626    ///     tokio::spawn(async move {
627    ///         time::sleep(time::Duration::from_secs(5)).await;
628    ///         shutdown.notify();
629    ///     });
630    ///
631    ///     // The `launch()` future resolves after ~5 seconds.
632    ///     let result = rocket.launch().await;
633    ///     assert!(result.is_ok());
634    ///
635    ///     Ok(())
636    /// }
637    /// ```
638    pub fn shutdown(&self) -> Shutdown {
639        self.shutdown.clone()
640    }
641
642    fn into_orbit(self) -> Rocket<Orbit> {
643        Rocket(Orbiting {
644            router: self.0.router,
645            fairings: self.0.fairings,
646            figment: self.0.figment,
647            config: self.0.config,
648            state: self.0.state,
649            shutdown: self.0.shutdown,
650        })
651    }
652
653    async fn _local_launch(self) -> Rocket<Orbit> {
654        let rocket = self.into_orbit();
655        rocket.fairings.handle_liftoff(&rocket).await;
656        launch_info!("{}{}", "🚀 ".emoji(), "Rocket has launched locally".primary().bold());
657        rocket
658    }
659
660    async fn _launch(self) -> Result<Rocket<Ignite>, Error> {
661        self.into_orbit()
662            .default_tcp_http_server(|rkt| Box::pin(async move {
663                rkt.fairings.handle_liftoff(&rkt).await;
664
665                let proto = rkt.config.tls_enabled().then(|| "https").unwrap_or("http");
666                let socket_addr = SocketAddr::new(rkt.config.address, rkt.config.port);
667                let addr = format!("{}://{}", proto, socket_addr);
668                launch_info!("{}{} {}",
669                    "🚀 ".emoji(),
670                    "Rocket has launched from".bold().primary().linger(),
671                    addr.underline());
672            }))
673            .await
674            .map(|rocket| rocket.into_ignite())
675    }
676}
677
678impl Rocket<Orbit> {
679    pub(crate) fn into_ignite(self) -> Rocket<Ignite> {
680        Rocket(Igniting {
681            router: self.0.router,
682            fairings: self.0.fairings,
683            figment: self.0.figment,
684            config: self.0.config,
685            state: self.0.state,
686            shutdown: self.0.shutdown,
687        })
688    }
689
690    /// Returns the finalized, active configuration. This is guaranteed to
691    /// remain stable after [`Rocket::ignite()`], through ignition and into
692    /// orbit.
693    ///
694    /// # Example
695    ///
696    /// ```rust,no_run
697    /// # #[macro_use] extern crate rocket;
698    /// use rocket::fairing::AdHoc;
699    ///
700    /// #[launch]
701    /// fn rocket() -> _ {
702    ///     rocket::build()
703    ///         .attach(AdHoc::on_liftoff("Config", |rocket| Box::pin(async move {
704    ///             println!("Rocket launch config: {:?}", rocket.config());
705    ///         })))
706    /// }
707    /// ```
708    pub fn config(&self) -> &Config {
709        &self.config
710    }
711
712    /// Returns a handle which can be used to trigger a shutdown and detect a
713    /// triggered shutdown.
714    ///
715    /// A completed graceful shutdown resolves the future returned by
716    /// [`Rocket::launch()`]. See [`Shutdown`] and
717    /// [`config::Shutdown`](crate::config::Shutdown) for details on graceful
718    /// shutdown.
719    ///
720    /// # Example
721    ///
722    /// ```rust,no_run
723    /// # #[macro_use] extern crate rocket;
724    /// use rocket::tokio::{self, time};
725    /// use rocket::fairing::AdHoc;
726    ///
727    /// #[launch]
728    /// fn rocket() -> _ {
729    ///     rocket::build()
730    ///         .attach(AdHoc::on_liftoff("Shutdown", |rocket| Box::pin(async move {
731    ///             let shutdown = rocket.shutdown();
732    ///             tokio::spawn(async move {
733    ///                 time::sleep(time::Duration::from_secs(5)).await;
734    ///                 shutdown.notify();
735    ///             });
736    ///         })))
737    /// }
738    /// ```
739    pub fn shutdown(&self) -> Shutdown {
740        self.shutdown.clone()
741    }
742}
743
744impl<P: Phase> Rocket<P> {
745    /// Returns an iterator over all of the routes mounted on this instance of
746    /// Rocket. The order is unspecified.
747    ///
748    /// # Example
749    ///
750    /// ```rust
751    /// # use rocket::*;
752    /// use rocket::Rocket;
753    /// use rocket::fairing::AdHoc;
754    ///
755    /// #[get("/hello")]
756    /// fn hello() -> &'static str {
757    ///     "Hello, world!"
758    /// }
759    ///
760    /// let rocket = rocket::build()
761    ///     .mount("/", routes![hello])
762    ///     .mount("/hi", routes![hello]);
763    ///
764    /// assert_eq!(rocket.routes().count(), 2);
765    /// assert!(rocket.routes().any(|r| r.uri == "/hello"));
766    /// assert!(rocket.routes().any(|r| r.uri == "/hi/hello"));
767    /// ```
768    pub fn routes(&self) -> impl Iterator<Item = &Route> {
769        match self.0.as_state_ref() {
770            StateRef::Build(p) => Either::Left(p.routes.iter()),
771            StateRef::Ignite(p) => Either::Right(p.router.routes()),
772            StateRef::Orbit(p) => Either::Right(p.router.routes()),
773        }
774    }
775
776    /// Returns an iterator over all of the catchers registered on this instance
777    /// of Rocket. The order is unspecified.
778    ///
779    /// # Example
780    ///
781    /// ```rust
782    /// # use rocket::*;
783    /// use rocket::Rocket;
784    /// use rocket::fairing::AdHoc;
785    ///
786    /// #[catch(404)] fn not_found() -> &'static str { "Nothing here, sorry!" }
787    /// #[catch(500)] fn just_500() -> &'static str { "Whoops!?" }
788    /// #[catch(default)] fn some_default() -> &'static str { "Everything else." }
789    ///
790    /// let rocket = rocket::build()
791    ///     .register("/foo", catchers![not_found])
792    ///     .register("/", catchers![just_500, some_default]);
793    ///
794    /// assert_eq!(rocket.catchers().count(), 3);
795    /// assert!(rocket.catchers().any(|c| c.code == Some(404) && c.base == "/foo"));
796    /// assert!(rocket.catchers().any(|c| c.code == Some(500) && c.base == "/"));
797    /// assert!(rocket.catchers().any(|c| c.code == None && c.base == "/"));
798    /// ```
799    pub fn catchers(&self) -> impl Iterator<Item = &Catcher> {
800        match self.0.as_state_ref() {
801            StateRef::Build(p) => Either::Left(p.catchers.iter()),
802            StateRef::Ignite(p) => Either::Right(p.router.catchers()),
803            StateRef::Orbit(p) => Either::Right(p.router.catchers()),
804        }
805    }
806
807    /// Returns `Some` of the managed state value for the type `T` if it is
808    /// being managed by `self`. Otherwise, returns `None`.
809    ///
810    /// # Example
811    ///
812    /// ```rust
813    /// #[derive(PartialEq, Debug)]
814    /// struct MyState(&'static str);
815    ///
816    /// let rocket = rocket::build().manage(MyState("hello!"));
817    /// assert_eq!(rocket.state::<MyState>().unwrap(), &MyState("hello!"));
818    /// ```
819    pub fn state<T: Send + Sync + 'static>(&self) -> Option<&T> {
820        match self.0.as_state_ref() {
821            StateRef::Build(p) => p.state.try_get(),
822            StateRef::Ignite(p) => p.state.try_get(),
823            StateRef::Orbit(p) => p.state.try_get(),
824        }
825    }
826
827    /// Returns the figment derived from the configuration provider set for
828    /// `self`. To extract a typed config, prefer to use
829    /// [`AdHoc::config()`](crate::fairing::AdHoc::config()).
830    ///
831    /// # Example
832    ///
833    /// ```rust
834    /// let rocket = rocket::build();
835    /// let figment = rocket.figment();
836    /// ```
837    pub fn figment(&self) -> &Figment {
838        match self.0.as_state_ref() {
839            StateRef::Build(p) => &p.figment,
840            StateRef::Ignite(p) => &p.figment,
841            StateRef::Orbit(p) => &p.figment,
842        }
843    }
844
845    pub(crate) async fn local_launch(self) -> Result<Rocket<Orbit>, Error> {
846        let rocket = match self.0.into_state() {
847            State::Build(s) => Rocket::from(s).ignite().await?._local_launch().await,
848            State::Ignite(s) => Rocket::from(s)._local_launch().await,
849            State::Orbit(s) => Rocket::from(s)
850        };
851
852        Ok(rocket)
853    }
854
855    /// Returns a `Future` that transitions this instance of `Rocket` from any
856    /// phase into the _orbit_ phase. When `await`ed, the future drives the
857    /// server forward, listening for and dispatching requests to mounted routes
858    /// and catchers.
859    ///
860    /// In addition to all of the processes that occur during
861    /// [ignition](Rocket::ignite()), a successful launch results in _liftoff_
862    /// fairings being executed _after_ binding to any respective network
863    /// interfaces but before serving the first request. Liftoff fairings are
864    /// run concurrently; resolution of all fairings is `await`ed before
865    /// resuming request serving.
866    ///
867    /// The `Future` resolves as an `Err` if any of the following occur:
868    ///
869    ///   * there is an error igniting; see [`Rocket::ignite()`].
870    ///   * there is an I/O error starting the server.
871    ///   * an unrecoverable, system-level error occurs while running.
872    ///
873    /// The `Future` resolves as an `Ok` if any of the following occur:
874    ///
875    ///   * graceful shutdown via [`Shutdown::notify()`] completes.
876    ///
877    /// The returned value on `Ok(())` is previously running instance.
878    ///
879    /// The `Future` does not resolve otherwise.
880    ///
881    /// # Error
882    ///
883    /// If there is a problem starting the application or the application fails
884    /// unexpectedly while running, an [`Error`] is returned. Note that a value
885    /// of type `Error` panics if dropped without first being inspected. See the
886    /// [`Error`] documentation for more information.
887    ///
888    /// # Example
889    ///
890    /// ```rust,no_run
891    /// #[rocket::main]
892    /// async fn main() {
893    ///     let result = rocket::build().launch().await;
894    ///
895    ///     // this is reachable only after `Shutdown::notify()` or `Ctrl+C`.
896    ///     println!("Rocket: deorbit.");
897    /// }
898    /// ```
899    pub async fn launch(self) -> Result<Rocket<Ignite>, Error> {
900        match self.0.into_state() {
901            State::Build(s) => Rocket::from(s).ignite().await?._launch().await,
902            State::Ignite(s) => Rocket::from(s)._launch().await,
903            State::Orbit(s) => Ok(Rocket::from(s).into_ignite())
904        }
905    }
906}
907
908#[doc(hidden)]
909impl<P: Phase> Deref for Rocket<P> {
910    type Target = P::State;
911
912    fn deref(&self) -> &Self::Target {
913        &self.0
914    }
915}
916
917#[doc(hidden)]
918impl<P: Phase> DerefMut for Rocket<P> {
919    fn deref_mut(&mut self) -> &mut Self::Target {
920        &mut self.0
921    }
922}
923
924impl<P: Phase> fmt::Debug for Rocket<P> {
925    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
926        self.0.fmt(f)
927    }
928}