2020-06-19 13:01:10 +00:00
|
|
|
use std::collections::HashMap;
|
2019-05-19 17:58:19 +00:00
|
|
|
|
2017-06-02 04:44:31 +00:00
|
|
|
use yansi::Paint;
|
2017-01-21 03:31:46 +00:00
|
|
|
use state::Container;
|
2020-09-03 05:41:31 +00:00
|
|
|
use figment::Figment;
|
2020-10-23 00:37:05 +00:00
|
|
|
use tokio::sync::mpsc;
|
|
|
|
use futures::future::FutureExt;
|
2017-01-21 03:31:46 +00:00
|
|
|
|
2020-10-23 00:37:05 +00:00
|
|
|
use crate::logger;
|
2020-09-03 05:41:31 +00:00
|
|
|
use crate::config::Config;
|
2020-07-30 06:07:22 +00:00
|
|
|
use crate::catcher::Catcher;
|
2019-06-13 01:48:02 +00:00
|
|
|
use crate::router::{Router, Route};
|
|
|
|
use crate::fairing::{Fairing, Fairings};
|
2020-04-14 12:28:36 +00:00
|
|
|
use crate::logger::PaintExt;
|
2020-07-23 02:22:32 +00:00
|
|
|
use crate::shutdown::Shutdown;
|
2019-06-13 01:48:02 +00:00
|
|
|
use crate::http::uri::Origin;
|
2020-10-23 00:37:05 +00:00
|
|
|
use crate::error::{Error, ErrorKind};
|
2016-04-01 23:54:53 +00:00
|
|
|
|
2016-11-04 13:35:04 +00:00
|
|
|
/// The main `Rocket` type: used to mount routes and catchers and launch the
|
2016-10-21 09:56:57 +00:00
|
|
|
/// application.
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
#[derive(Debug)]
|
2016-04-01 23:54:53 +00:00
|
|
|
pub struct Rocket {
|
2020-06-28 05:59:40 +00:00
|
|
|
pub(crate) config: Config,
|
2020-09-03 05:41:31 +00:00
|
|
|
pub(crate) figment: Figment,
|
UTF-8 routes. Forms revamp. Temp files. Capped.
So. Many. Changes.
This is an insane commit: simultaneously one of the best (because of all
the wonderful improvements!) and one of the worst (because it is just
massive) in the project's history.
Routing:
* All UTF-8 characters are accepted everywhere in route paths. (#998)
* `path` is now `uri` in `route` attribute: `#[route(GET, path = "..")]`
becomes `#[route(GET, uri = "..")]`.
Forms Revamp
* All form related types now reside in a new `form` module.
* Multipart forms are supported. (resolves #106)
* Collections are supported in forms and queries. (resolves #205)
* Nested structures in forms and queries are supported. (resolves #313)
* Form fields can be ad-hoc validated with `#[field(validate = expr)]`.
* `FromFormValue` is now `FromFormField`, blanket implements `FromForm`.
* Form field values are always percent-decoded apriori.
Temporary Files
* A new `TempFile` data and form guard allows streaming data directly to a
file which can then be persisted.
* A new `temp_dir` config parameter specifies where to store `TempFile`.
* The limits `file` and `file/$ext`, where `$ext` is the file extension,
determines the data limit for a `TempFile`.
Capped
* A new `Capped` type is used to indicate when data has been truncated due to
incoming data limits. It allows checking whether data is complete or
truncated.
* `DataStream` methods return `Capped` types.
* `DataStream` API has been revamped to account for `Capped` types.
* Several `Capped<T>` types implement `FromData`, `FromForm`.
* HTTP 413 (Payload Too Large) errors are now returned when data limits are
exceeded. (resolves #972)
Hierarchical Limits
* Data limits are now hierarchical, delimited with `/`. A limit of `a/b/c`
falls back to `a/b` then `a`.
Core
* `&RawStr` no longer implements `FromParam`.
* `&str` implements `FromParam`, `FromData`, `FromForm`.
* `FromTransformedData` was removed.
* `FromData` gained a lifetime for use with request-local data.
* The default error HTML is more compact.
* `&Config` is a request guard.
* The `DataStream` interface was entirely revamped.
* `State` is only exported via `rocket::State`.
* A `request::local_cache!()` macro was added for storing values in
request-local cache without consideration for type uniqueness by using a
locally generated anonymous type.
* `Request::get_param()` is now `Request::param()`.
* `Request::get_segments()` is now `Request::segments()`, takes a range.
* `Request::get_query_value()` is now `Request::query_value()`, can parse any
`FromForm` including sequences.
* `std::io::Error` implements `Responder` like `Debug<std::io::Error>`.
* `(Status, R)` where `R: Responder` implements `Responder` by overriding the
`Status` of `R`.
* The name of a route is printed first during route matching.
* `FlashMessage` now only has one lifetime generic.
HTTP
* `RawStr` implements `serde::{Serialize, Deserialize}`.
* `RawStr` implements _many_ more methods, in particular, those related to the
`Pattern` API.
* `RawStr::from_str()` is now `RawStr::new()`.
* `RawStr::url_decode()` and `RawStr::url_decode_lossy()` only allocate as
necessary, return `Cow`.
* `Status` implements `Default` with `Status::Ok`.
* `Status` implements `PartialEq`, `Eq`, `Hash`, `PartialOrd`, `Ord`.
* Authority and origin part of `Absolute` can be modified with new
`Absolute::{with,set}_authority()`, `Absolute::{with,set}_origin()` methods.
* `Origin::segments()` was removed in favor of methods split into query and
path parts and into raw and decoded versions.
* The `Segments` iterator is smarter, returns decoded `&str` items.
* `Segments::into_path_buf()` is now `Segments::to_path_buf()`.
* A new `QuerySegments` is the analogous query segment iterator.
* Once set, `expires` on private cookies is not overwritten. (resolves #1506)
* `Origin::path()` and `Origin::query()` return `&RawStr`, not `&str`.
Codegen
* Preserve more spans in `uri!` macro.
* Preserve spans `FromForm` field types.
* All dynamic parameters in a query string must typecheck as `FromForm`.
* `FromFormValue` derive removed; `FromFormField` added.
* The `form` `FromForm` and `FromFormField` field attribute is now named
`field`. `#[form(field = ..)]` is now `#[field(name = ..)]`.
Contrib
* `Json` implements `FromForm`.
* `MsgPack` implements `FromForm`.
* The `json!` macro is exported as `rocket_contrib::json::json!`.
* Added clarifying docs to `StaticFiles`.
Examples
* `form_validation` and `form_kitchen_sink` removed in favor of `forms`.
* The `hello_world` example uses unicode in paths.
* The `json` example only allocates as necessary.
Internal
* Codegen uses new `exports` module with the following conventions:
- Locals starts with `__` and are lowercased.
- Rocket modules start with `_` and are lowercased.
- `std` types start with `_` and are titlecased.
- Rocket types are titlecased.
* A `header` module was added to `http`, contains header types.
* `SAFETY` is used as doc-string keyword for `unsafe` related comments.
* The `Uri` parser no longer recognizes Rocket route URIs.
2020-10-30 03:50:06 +00:00
|
|
|
pub(crate) managed_state: Container![Send + Sync],
|
2020-10-23 00:37:05 +00:00
|
|
|
pub(crate) router: Router,
|
|
|
|
pub(crate) default_catcher: Option<Catcher>,
|
|
|
|
pub(crate) catchers: HashMap<u16, Catcher>,
|
|
|
|
pub(crate) fairings: Fairings,
|
|
|
|
pub(crate) shutdown_receiver: Option<mpsc::Receiver<()>>,
|
2020-07-23 02:22:32 +00:00
|
|
|
pub(crate) shutdown_handle: Shutdown,
|
2020-06-14 15:57:51 +00:00
|
|
|
}
|
|
|
|
|
2019-05-19 17:58:19 +00:00
|
|
|
impl Rocket {
|
2016-11-04 13:35:04 +00:00
|
|
|
/// Create a new `Rocket` application using the configuration information in
|
|
|
|
/// `Rocket.toml`. If the file does not exist or if there is an I/O error
|
2020-07-09 02:29:18 +00:00
|
|
|
/// reading the file, the defaults, overridden by any environment-based
|
2021-03-10 10:16:59 +00:00
|
|
|
/// parameters, are used. See the [`config`](crate::config) documentation
|
|
|
|
/// for more information on defaults.
|
2016-11-04 13:35:04 +00:00
|
|
|
///
|
2018-10-06 13:25:17 +00:00
|
|
|
/// This method is typically called through the
|
2019-06-13 01:48:02 +00:00
|
|
|
/// [`rocket::ignite()`](crate::ignite) alias.
|
2016-11-04 13:35:04 +00:00
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
2020-06-07 06:22:04 +00:00
|
|
|
/// If there is an error reading configuration sources, this function prints
|
|
|
|
/// a nice error message and then exits the process.
|
2016-11-04 13:35:04 +00:00
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # {
|
|
|
|
/// rocket::ignite()
|
|
|
|
/// # };
|
|
|
|
/// ```
|
2021-03-09 02:18:15 +00:00
|
|
|
#[track_caller]
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
#[inline(always)]
|
2016-11-04 13:35:04 +00:00
|
|
|
pub fn ignite() -> Rocket {
|
2020-09-03 05:41:31 +00:00
|
|
|
Rocket::custom(Config::figment())
|
2016-11-04 13:35:04 +00:00
|
|
|
}
|
|
|
|
|
2020-09-03 05:41:31 +00:00
|
|
|
/// Creates a new `Rocket` application using the supplied configuration
|
|
|
|
/// provider. This method is typically called through the
|
2020-10-22 10:52:56 +00:00
|
|
|
/// [`rocket::custom()`](crate::custom()) alias.
|
2020-09-03 05:41:31 +00:00
|
|
|
///
|
|
|
|
/// # Panics
|
2016-11-04 13:35:04 +00:00
|
|
|
///
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
/// If there is an error reading a [`Config`] from `provider`, function
|
|
|
|
/// prints a nice error message and then exits the process.
|
2016-11-04 13:35:04 +00:00
|
|
|
///
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
/// # Example
|
2016-11-04 13:35:04 +00:00
|
|
|
///
|
2021-03-09 02:18:15 +00:00
|
|
|
/// ```rust
|
2020-09-03 05:41:31 +00:00
|
|
|
/// use figment::{Figment, providers::{Toml, Env, Format}};
|
|
|
|
///
|
|
|
|
/// #[rocket::launch]
|
|
|
|
/// fn rocket() -> _ {
|
|
|
|
/// let figment = Figment::from(rocket::Config::default())
|
|
|
|
/// .merge(Toml::file("MyApp.toml").nested())
|
2021-03-09 02:18:15 +00:00
|
|
|
/// .merge(Env::prefixed("MY_APP_").global());
|
2020-09-03 05:41:31 +00:00
|
|
|
///
|
|
|
|
/// rocket::custom(figment)
|
|
|
|
/// }
|
2016-11-04 13:35:04 +00:00
|
|
|
/// ```
|
2021-03-09 02:18:15 +00:00
|
|
|
#[track_caller]
|
2020-09-03 05:41:31 +00:00
|
|
|
pub fn custom<T: figment::Provider>(provider: T) -> Rocket {
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
let config = Config::from(&provider);
|
|
|
|
let figment = Figment::from(provider);
|
|
|
|
logger::init(&config);
|
2020-12-23 20:37:54 +00:00
|
|
|
config.pretty_print(&figment);
|
2016-11-04 13:35:04 +00:00
|
|
|
|
UTF-8 routes. Forms revamp. Temp files. Capped.
So. Many. Changes.
This is an insane commit: simultaneously one of the best (because of all
the wonderful improvements!) and one of the worst (because it is just
massive) in the project's history.
Routing:
* All UTF-8 characters are accepted everywhere in route paths. (#998)
* `path` is now `uri` in `route` attribute: `#[route(GET, path = "..")]`
becomes `#[route(GET, uri = "..")]`.
Forms Revamp
* All form related types now reside in a new `form` module.
* Multipart forms are supported. (resolves #106)
* Collections are supported in forms and queries. (resolves #205)
* Nested structures in forms and queries are supported. (resolves #313)
* Form fields can be ad-hoc validated with `#[field(validate = expr)]`.
* `FromFormValue` is now `FromFormField`, blanket implements `FromForm`.
* Form field values are always percent-decoded apriori.
Temporary Files
* A new `TempFile` data and form guard allows streaming data directly to a
file which can then be persisted.
* A new `temp_dir` config parameter specifies where to store `TempFile`.
* The limits `file` and `file/$ext`, where `$ext` is the file extension,
determines the data limit for a `TempFile`.
Capped
* A new `Capped` type is used to indicate when data has been truncated due to
incoming data limits. It allows checking whether data is complete or
truncated.
* `DataStream` methods return `Capped` types.
* `DataStream` API has been revamped to account for `Capped` types.
* Several `Capped<T>` types implement `FromData`, `FromForm`.
* HTTP 413 (Payload Too Large) errors are now returned when data limits are
exceeded. (resolves #972)
Hierarchical Limits
* Data limits are now hierarchical, delimited with `/`. A limit of `a/b/c`
falls back to `a/b` then `a`.
Core
* `&RawStr` no longer implements `FromParam`.
* `&str` implements `FromParam`, `FromData`, `FromForm`.
* `FromTransformedData` was removed.
* `FromData` gained a lifetime for use with request-local data.
* The default error HTML is more compact.
* `&Config` is a request guard.
* The `DataStream` interface was entirely revamped.
* `State` is only exported via `rocket::State`.
* A `request::local_cache!()` macro was added for storing values in
request-local cache without consideration for type uniqueness by using a
locally generated anonymous type.
* `Request::get_param()` is now `Request::param()`.
* `Request::get_segments()` is now `Request::segments()`, takes a range.
* `Request::get_query_value()` is now `Request::query_value()`, can parse any
`FromForm` including sequences.
* `std::io::Error` implements `Responder` like `Debug<std::io::Error>`.
* `(Status, R)` where `R: Responder` implements `Responder` by overriding the
`Status` of `R`.
* The name of a route is printed first during route matching.
* `FlashMessage` now only has one lifetime generic.
HTTP
* `RawStr` implements `serde::{Serialize, Deserialize}`.
* `RawStr` implements _many_ more methods, in particular, those related to the
`Pattern` API.
* `RawStr::from_str()` is now `RawStr::new()`.
* `RawStr::url_decode()` and `RawStr::url_decode_lossy()` only allocate as
necessary, return `Cow`.
* `Status` implements `Default` with `Status::Ok`.
* `Status` implements `PartialEq`, `Eq`, `Hash`, `PartialOrd`, `Ord`.
* Authority and origin part of `Absolute` can be modified with new
`Absolute::{with,set}_authority()`, `Absolute::{with,set}_origin()` methods.
* `Origin::segments()` was removed in favor of methods split into query and
path parts and into raw and decoded versions.
* The `Segments` iterator is smarter, returns decoded `&str` items.
* `Segments::into_path_buf()` is now `Segments::to_path_buf()`.
* A new `QuerySegments` is the analogous query segment iterator.
* Once set, `expires` on private cookies is not overwritten. (resolves #1506)
* `Origin::path()` and `Origin::query()` return `&RawStr`, not `&str`.
Codegen
* Preserve more spans in `uri!` macro.
* Preserve spans `FromForm` field types.
* All dynamic parameters in a query string must typecheck as `FromForm`.
* `FromFormValue` derive removed; `FromFormField` added.
* The `form` `FromForm` and `FromFormField` field attribute is now named
`field`. `#[form(field = ..)]` is now `#[field(name = ..)]`.
Contrib
* `Json` implements `FromForm`.
* `MsgPack` implements `FromForm`.
* The `json!` macro is exported as `rocket_contrib::json::json!`.
* Added clarifying docs to `StaticFiles`.
Examples
* `form_validation` and `form_kitchen_sink` removed in favor of `forms`.
* The `hello_world` example uses unicode in paths.
* The `json` example only allocates as necessary.
Internal
* Codegen uses new `exports` module with the following conventions:
- Locals starts with `__` and are lowercased.
- Rocket modules start with `_` and are lowercased.
- `std` types start with `_` and are titlecased.
- Rocket types are titlecased.
* A `header` module was added to `http`, contains header types.
* `SAFETY` is used as doc-string keyword for `unsafe` related comments.
* The `Uri` parser no longer recognizes Rocket route URIs.
2020-10-30 03:50:06 +00:00
|
|
|
let managed_state = <Container![Send + Sync]>::new();
|
2019-08-25 02:19:11 +00:00
|
|
|
let (shutdown_sender, shutdown_receiver) = mpsc::channel(1);
|
2020-06-28 05:59:40 +00:00
|
|
|
Rocket {
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
config, figment, managed_state,
|
2020-07-23 02:22:32 +00:00
|
|
|
shutdown_handle: Shutdown(shutdown_sender),
|
2016-11-04 13:35:04 +00:00
|
|
|
router: Router::new(),
|
2020-07-30 06:07:22 +00:00
|
|
|
default_catcher: None,
|
|
|
|
catchers: HashMap::new(),
|
2017-09-05 03:11:10 +00:00
|
|
|
fairings: Fairings::new(),
|
2019-08-25 02:19:11 +00:00
|
|
|
shutdown_receiver: Some(shutdown_receiver),
|
2020-06-28 05:59:40 +00:00
|
|
|
}
|
2016-11-04 13:35:04 +00:00
|
|
|
}
|
|
|
|
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
/// Resets the configuration in `self` to that provided by `provider`.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Like [`Rocket::custom()`], panics if `provider` does not provide a valid
|
|
|
|
/// [`Config`]. The error message is printed.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// To modify only some values, use the existing `config`:
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use std::net::Ipv4Addr;
|
|
|
|
///
|
|
|
|
/// let config = rocket::Config {
|
|
|
|
/// port: 7777,
|
|
|
|
/// address: Ipv4Addr::new(18, 127, 0, 1).into(),
|
|
|
|
/// ..rocket::Config::default()
|
|
|
|
/// };
|
|
|
|
///
|
|
|
|
/// let rocket = rocket::custom(&config);
|
|
|
|
/// assert_eq!(rocket.config().port, 7777);
|
|
|
|
/// assert_eq!(rocket.config().address, Ipv4Addr::new(18, 127, 0, 1));
|
|
|
|
///
|
|
|
|
/// // Modifying the existing config:
|
|
|
|
/// let mut new_config = rocket.config().clone();
|
|
|
|
/// new_config.port = 8888;
|
|
|
|
///
|
|
|
|
/// let rocket = rocket.reconfigure(new_config);
|
|
|
|
/// assert_eq!(rocket.config().port, 8888);
|
|
|
|
/// assert_eq!(rocket.config().address, Ipv4Addr::new(18, 127, 0, 1));
|
|
|
|
///
|
|
|
|
/// // Modifying the existing figment:
|
|
|
|
/// let mut new_figment = rocket.figment().clone()
|
|
|
|
/// .merge(("address", "171.64.200.10"));
|
|
|
|
///
|
|
|
|
/// let rocket = rocket.reconfigure(new_figment);
|
|
|
|
/// assert_eq!(rocket.config().port, 8888);
|
|
|
|
/// assert_eq!(rocket.config().address, Ipv4Addr::new(171, 64, 200, 10));
|
|
|
|
/// ```
|
|
|
|
#[inline]
|
|
|
|
#[track_caller]
|
|
|
|
pub fn reconfigure<T: figment::Provider>(mut self, provider: T) -> Rocket {
|
|
|
|
self.config = Config::from(&provider);
|
|
|
|
self.figment = Figment::from(provider);
|
|
|
|
logger::init(&self.config);
|
|
|
|
self.config.pretty_print(&self.figment);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2016-11-04 13:35:04 +00:00
|
|
|
/// Mounts all of the routes in the supplied vector at the given `base`
|
|
|
|
/// path. Mounting a route with path `path` at path `base` makes the route
|
|
|
|
/// available at `base/path`.
|
|
|
|
///
|
2017-05-19 10:29:08 +00:00
|
|
|
/// # Panics
|
|
|
|
///
|
Overhaul URI types.
This is fairly large commit with several entangled logical changes.
The primary change in this commit is to completely overhaul how URI
handling in Rocket works. Prior to this commit, the `Uri` type acted as
an origin API. Its parser was minimal and lenient, allowing URIs that
were invalid according to RFC 7230. By contrast, the new `Uri` type
brings with it a strict RFC 7230 compliant parser. The `Uri` type now
represents any kind of valid URI, not simply `Origin` types. Three new
URI types were introduced:
* `Origin` - represents valid origin URIs
* `Absolute` - represents valid absolute URIs
* `Authority` - represents valid authority URIs
The `Origin` type replaces `Uri` in many cases:
* As fields and method inputs of `Route`
* The `&Uri` request guard is now `&Origin`
* The `uri!` macro produces an `Origin` instead of a `Uri`
The strict nature of URI parsing cascaded into the following changes:
* Several `Route` methods now `panic!` on invalid URIs
* The `Rocket::mount()` method is (correctly) stricter with URIs
* The `Redirect` constructors take a `TryInto<Uri>` type
* Dispatching of a `LocalRequest` correctly validates URIs
Overall, URIs are now properly and uniformly handled throughout Rocket's
codebase, resulting in a more reliable and correct system.
In addition to these URI changes, the following changes are also part of
this commit:
* The `LocalRequest::cloned_dispatch()` method was removed in favor of
chaining `.clone().dispatch()`.
* The entire Rocket codebase uses `crate` instead of `pub(crate)` as a
visibility modifier.
* Rocket uses the `crate_visibility_modifier` and `try_from` features.
A note on unsafety: this commit introduces many uses of `unsafe` in the
URI parser. All of these uses are a result of unsafely transforming byte
slices (`&[u8]` or similar) into strings (`&str`). The parser ensures
that these casts are safe, but of course, we must label their use
`unsafe`. The parser was written to be as generic and efficient as
possible and thus can parse directly from byte sources. Rocket, however,
does not make use of this fact and so would be able to remove all uses
of `unsafe` by parsing from an existing `&str`. This should be
considered in the future.
Fixes #443.
Resolves #263.
2018-07-29 01:26:15 +00:00
|
|
|
/// Panics if the `base` mount point is not a valid static path: a valid
|
|
|
|
/// origin URI without dynamic parameters.
|
|
|
|
///
|
|
|
|
/// Panics if any route's URI is not a valid origin URI. This kind of panic
|
|
|
|
/// is guaranteed not to occur if the routes were generated using Rocket's
|
|
|
|
/// code generation.
|
2017-05-19 10:29:08 +00:00
|
|
|
///
|
2016-11-04 13:35:04 +00:00
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// Use the `routes!` macro to mount routes created using the code
|
|
|
|
/// generation facilities. Requests to the `/hello/world` URI will be
|
|
|
|
/// dispatched to the `hi` route.
|
|
|
|
///
|
2020-06-16 12:01:26 +00:00
|
|
|
/// ```rust,no_run
|
2018-06-28 15:55:15 +00:00
|
|
|
/// # #[macro_use] extern crate rocket;
|
2016-11-04 13:35:04 +00:00
|
|
|
/// #
|
|
|
|
/// #[get("/world")]
|
|
|
|
/// fn hi() -> &'static str {
|
|
|
|
/// "Hello!"
|
|
|
|
/// }
|
|
|
|
///
|
2020-07-22 23:10:02 +00:00
|
|
|
/// #[launch]
|
2020-06-16 12:01:26 +00:00
|
|
|
/// fn rocket() -> rocket::Rocket {
|
2016-11-04 13:35:04 +00:00
|
|
|
/// rocket::ignite().mount("/hello", routes![hi])
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Manually create a route named `hi` at path `"/world"` mounted at base
|
|
|
|
/// `"/hello"`. Requests to the `/hello/world` URI will be dispatched to the
|
|
|
|
/// `hi` route.
|
|
|
|
///
|
|
|
|
/// ```rust
|
2016-12-15 08:47:31 +00:00
|
|
|
/// use rocket::{Request, Route, Data};
|
2019-08-07 00:08:00 +00:00
|
|
|
/// use rocket::handler::{HandlerFuture, Outcome};
|
2016-11-04 13:35:04 +00:00
|
|
|
/// use rocket::http::Method::*;
|
|
|
|
///
|
2019-08-07 00:08:00 +00:00
|
|
|
/// fn hi<'r>(req: &'r Request, _: Data) -> HandlerFuture<'r> {
|
2020-06-21 12:54:37 +00:00
|
|
|
/// Outcome::from(req, "Hello!").pin()
|
2016-11-04 13:35:04 +00:00
|
|
|
/// }
|
|
|
|
///
|
2020-06-14 15:57:55 +00:00
|
|
|
/// # let _ = async { // We don't actually want to launch the server in an example.
|
2016-11-04 13:35:04 +00:00
|
|
|
/// rocket::ignite().mount("/hello", vec![Route::new(Get, "/world", hi)])
|
2020-06-14 15:57:55 +00:00
|
|
|
/// # .launch().await;
|
|
|
|
/// # };
|
2016-11-04 13:35:04 +00:00
|
|
|
/// ```
|
2018-08-13 07:43:29 +00:00
|
|
|
pub fn mount<R: Into<Vec<Route>>>(mut self, base: &str, routes: R) -> Self {
|
2020-06-14 15:57:51 +00:00
|
|
|
let base_uri = Origin::parse_owned(base.to_string())
|
2018-07-30 01:24:25 +00:00
|
|
|
.unwrap_or_else(|e| {
|
2020-07-29 23:38:24 +00:00
|
|
|
error!("Invalid mount point URI: {}.", Paint::white(base));
|
2018-07-30 01:24:25 +00:00
|
|
|
panic!("Error: {}", e);
|
|
|
|
});
|
Overhaul URI types.
This is fairly large commit with several entangled logical changes.
The primary change in this commit is to completely overhaul how URI
handling in Rocket works. Prior to this commit, the `Uri` type acted as
an origin API. Its parser was minimal and lenient, allowing URIs that
were invalid according to RFC 7230. By contrast, the new `Uri` type
brings with it a strict RFC 7230 compliant parser. The `Uri` type now
represents any kind of valid URI, not simply `Origin` types. Three new
URI types were introduced:
* `Origin` - represents valid origin URIs
* `Absolute` - represents valid absolute URIs
* `Authority` - represents valid authority URIs
The `Origin` type replaces `Uri` in many cases:
* As fields and method inputs of `Route`
* The `&Uri` request guard is now `&Origin`
* The `uri!` macro produces an `Origin` instead of a `Uri`
The strict nature of URI parsing cascaded into the following changes:
* Several `Route` methods now `panic!` on invalid URIs
* The `Rocket::mount()` method is (correctly) stricter with URIs
* The `Redirect` constructors take a `TryInto<Uri>` type
* Dispatching of a `LocalRequest` correctly validates URIs
Overall, URIs are now properly and uniformly handled throughout Rocket's
codebase, resulting in a more reliable and correct system.
In addition to these URI changes, the following changes are also part of
this commit:
* The `LocalRequest::cloned_dispatch()` method was removed in favor of
chaining `.clone().dispatch()`.
* The entire Rocket codebase uses `crate` instead of `pub(crate)` as a
visibility modifier.
* Rocket uses the `crate_visibility_modifier` and `try_from` features.
A note on unsafety: this commit introduces many uses of `unsafe` in the
URI parser. All of these uses are a result of unsafely transforming byte
slices (`&[u8]` or similar) into strings (`&str`). The parser ensures
that these casts are safe, but of course, we must label their use
`unsafe`. The parser was written to be as generic and efficient as
possible and thus can parse directly from byte sources. Rocket, however,
does not make use of this fact and so would be able to remove all uses
of `unsafe` by parsing from an existing `&str`. This should be
considered in the future.
Fixes #443.
Resolves #263.
2018-07-29 01:26:15 +00:00
|
|
|
|
2018-07-30 01:24:25 +00:00
|
|
|
if base_uri.query().is_some() {
|
2020-07-29 23:38:24 +00:00
|
|
|
error!("Mount point '{}' contains query string.", base);
|
2018-07-30 01:24:25 +00:00
|
|
|
panic!("Invalid mount point.");
|
|
|
|
}
|
Overhaul URI types.
This is fairly large commit with several entangled logical changes.
The primary change in this commit is to completely overhaul how URI
handling in Rocket works. Prior to this commit, the `Uri` type acted as
an origin API. Its parser was minimal and lenient, allowing URIs that
were invalid according to RFC 7230. By contrast, the new `Uri` type
brings with it a strict RFC 7230 compliant parser. The `Uri` type now
represents any kind of valid URI, not simply `Origin` types. Three new
URI types were introduced:
* `Origin` - represents valid origin URIs
* `Absolute` - represents valid absolute URIs
* `Authority` - represents valid authority URIs
The `Origin` type replaces `Uri` in many cases:
* As fields and method inputs of `Route`
* The `&Uri` request guard is now `&Origin`
* The `uri!` macro produces an `Origin` instead of a `Uri`
The strict nature of URI parsing cascaded into the following changes:
* Several `Route` methods now `panic!` on invalid URIs
* The `Rocket::mount()` method is (correctly) stricter with URIs
* The `Redirect` constructors take a `TryInto<Uri>` type
* Dispatching of a `LocalRequest` correctly validates URIs
Overall, URIs are now properly and uniformly handled throughout Rocket's
codebase, resulting in a more reliable and correct system.
In addition to these URI changes, the following changes are also part of
this commit:
* The `LocalRequest::cloned_dispatch()` method was removed in favor of
chaining `.clone().dispatch()`.
* The entire Rocket codebase uses `crate` instead of `pub(crate)` as a
visibility modifier.
* Rocket uses the `crate_visibility_modifier` and `try_from` features.
A note on unsafety: this commit introduces many uses of `unsafe` in the
URI parser. All of these uses are a result of unsafely transforming byte
slices (`&[u8]` or similar) into strings (`&str`). The parser ensures
that these casts are safe, but of course, we must label their use
`unsafe`. The parser was written to be as generic and efficient as
possible and thus can parse directly from byte sources. Rocket, however,
does not make use of this fact and so would be able to remove all uses
of `unsafe` by parsing from an existing `&str`. This should be
considered in the future.
Fixes #443.
Resolves #263.
2018-07-29 01:26:15 +00:00
|
|
|
|
2020-10-22 10:27:04 +00:00
|
|
|
info!("{}{} {}{}",
|
|
|
|
Paint::emoji("🛰 "),
|
|
|
|
Paint::magenta("Mounting"),
|
|
|
|
Paint::blue(&base_uri),
|
|
|
|
Paint::magenta(":"));
|
|
|
|
|
|
|
|
for route in routes.into() {
|
2021-03-17 07:46:33 +00:00
|
|
|
let mounted_route = route.clone()
|
|
|
|
.map_base(|old| format!("{}{}", base, old))
|
2020-10-22 10:27:04 +00:00
|
|
|
.unwrap_or_else(|e| {
|
2021-03-17 07:46:33 +00:00
|
|
|
error_!("Route `{}` has a malformed URI.", route);
|
2020-10-22 10:27:04 +00:00
|
|
|
error_!("{}", e);
|
|
|
|
panic!("Invalid route URI.");
|
|
|
|
});
|
|
|
|
|
2021-03-17 07:46:33 +00:00
|
|
|
info_!("{}", mounted_route);
|
|
|
|
self.router.add(mounted_route);
|
2020-10-22 10:27:04 +00:00
|
|
|
}
|
|
|
|
|
2016-04-01 23:54:53 +00:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2016-11-04 13:35:04 +00:00
|
|
|
/// Registers all of the catchers in the supplied vector.
|
2016-11-05 18:35:21 +00:00
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
2020-06-16 12:01:26 +00:00
|
|
|
/// ```rust,no_run
|
2018-09-20 04:14:30 +00:00
|
|
|
/// # #[macro_use] extern crate rocket;
|
2018-09-17 03:52:07 +00:00
|
|
|
/// use rocket::Request;
|
2016-11-05 18:35:21 +00:00
|
|
|
///
|
2017-09-23 02:04:14 +00:00
|
|
|
/// #[catch(500)]
|
2016-11-05 18:35:21 +00:00
|
|
|
/// fn internal_error() -> &'static str {
|
|
|
|
/// "Whoops! Looks like we messed up."
|
|
|
|
/// }
|
|
|
|
///
|
2017-09-23 02:04:14 +00:00
|
|
|
/// #[catch(400)]
|
2016-11-05 18:35:21 +00:00
|
|
|
/// fn not_found(req: &Request) -> String {
|
|
|
|
/// format!("I couldn't find '{}'. Try something else?", req.uri())
|
|
|
|
/// }
|
|
|
|
///
|
2020-07-22 23:10:02 +00:00
|
|
|
/// #[launch]
|
2020-06-16 12:01:26 +00:00
|
|
|
/// fn rocket() -> rocket::Rocket {
|
|
|
|
/// rocket::ignite().register(catchers![internal_error, not_found])
|
2016-11-05 18:35:21 +00:00
|
|
|
/// }
|
|
|
|
/// ```
|
2018-09-16 08:47:51 +00:00
|
|
|
pub fn register(mut self, catchers: Vec<Catcher>) -> Self {
|
2020-10-22 10:27:04 +00:00
|
|
|
info!("{}{}", Paint::emoji("👾 "), Paint::magenta("Catchers:"));
|
|
|
|
|
|
|
|
for catcher in catchers {
|
|
|
|
info_!("{}", catcher);
|
|
|
|
|
|
|
|
let existing = match catcher.code {
|
|
|
|
Some(code) => self.catchers.insert(code, catcher),
|
|
|
|
None => self.default_catcher.replace(catcher)
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(existing) = existing {
|
|
|
|
warn_!("Replacing existing '{}' catcher.", existing);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-06 10:26:43 +00:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2017-01-21 03:31:46 +00:00
|
|
|
/// Add `state` to the state managed by this instance of Rocket.
|
|
|
|
///
|
2017-02-03 02:16:57 +00:00
|
|
|
/// This method can be called any number of times as long as each call
|
2017-02-06 18:40:43 +00:00
|
|
|
/// refers to a different `T`.
|
2017-02-03 02:16:57 +00:00
|
|
|
///
|
2017-01-21 03:31:46 +00:00
|
|
|
/// Managed state can be retrieved by any request handler via the
|
2019-06-13 01:48:02 +00:00
|
|
|
/// [`State`](crate::State) request guard. In particular, if a value of type `T`
|
2018-10-06 13:25:17 +00:00
|
|
|
/// is managed by Rocket, adding `State<T>` to the list of arguments in a
|
|
|
|
/// request handler instructs Rocket to retrieve the managed value.
|
2017-01-21 03:31:46 +00:00
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Panics if state of type `T` is already being managed.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
2020-06-16 12:01:26 +00:00
|
|
|
/// ```rust,no_run
|
2018-06-28 15:55:15 +00:00
|
|
|
/// # #[macro_use] extern crate rocket;
|
2017-01-21 03:31:46 +00:00
|
|
|
/// use rocket::State;
|
|
|
|
///
|
|
|
|
/// struct MyValue(usize);
|
|
|
|
///
|
|
|
|
/// #[get("/")]
|
|
|
|
/// fn index(state: State<MyValue>) -> String {
|
|
|
|
/// format!("The stateful value is: {}", state.0)
|
|
|
|
/// }
|
|
|
|
///
|
2020-07-22 23:10:02 +00:00
|
|
|
/// #[launch]
|
2020-06-16 12:01:26 +00:00
|
|
|
/// fn rocket() -> rocket::Rocket {
|
2017-01-21 03:31:46 +00:00
|
|
|
/// rocket::ignite()
|
2017-02-02 10:16:21 +00:00
|
|
|
/// .mount("/", routes![index])
|
2017-01-21 03:31:46 +00:00
|
|
|
/// .manage(MyValue(10))
|
|
|
|
/// }
|
|
|
|
/// ```
|
2017-05-19 10:29:08 +00:00
|
|
|
#[inline]
|
2020-10-22 10:27:04 +00:00
|
|
|
pub fn manage<T: Send + Sync + 'static>(self, state: T) -> Self {
|
2020-06-28 05:59:40 +00:00
|
|
|
let type_name = std::any::type_name::<T>();
|
2020-10-22 10:27:04 +00:00
|
|
|
if !self.managed_state.set(state) {
|
|
|
|
error!("State for type '{}' is already being managed!", type_name);
|
|
|
|
panic!("Aborting due to duplicately managed state.");
|
|
|
|
}
|
2017-01-21 03:31:46 +00:00
|
|
|
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2018-07-03 01:18:41 +00:00
|
|
|
/// Attaches a fairing to this instance of Rocket. If the fairing is an
|
|
|
|
/// _attach_ fairing, it is run immediately. All other kinds of fairings
|
|
|
|
/// will be executed at their appropriate time.
|
2017-04-20 20:43:01 +00:00
|
|
|
///
|
2017-05-15 04:46:01 +00:00
|
|
|
/// # Example
|
2017-04-20 20:43:01 +00:00
|
|
|
///
|
2020-06-16 12:01:26 +00:00
|
|
|
/// ```rust,no_run
|
2018-09-20 04:14:30 +00:00
|
|
|
/// # #[macro_use] extern crate rocket;
|
2017-05-15 04:46:01 +00:00
|
|
|
/// use rocket::Rocket;
|
|
|
|
/// use rocket::fairing::AdHoc;
|
2017-04-20 20:43:01 +00:00
|
|
|
///
|
2020-07-22 23:10:02 +00:00
|
|
|
/// #[launch]
|
2020-06-16 12:01:26 +00:00
|
|
|
/// fn rocket() -> rocket::Rocket {
|
2017-04-20 20:43:01 +00:00
|
|
|
/// rocket::ignite()
|
2018-08-14 16:14:06 +00:00
|
|
|
/// .attach(AdHoc::on_launch("Launch Message", |_| {
|
|
|
|
/// println!("Rocket is launching!");
|
|
|
|
/// }))
|
2017-04-20 20:43:01 +00:00
|
|
|
/// }
|
|
|
|
/// ```
|
2017-05-15 04:46:01 +00:00
|
|
|
pub fn attach<F: Fairing>(mut self, fairing: F) -> Self {
|
2020-10-22 10:27:04 +00:00
|
|
|
let future = async move {
|
|
|
|
let fairing = Box::new(fairing);
|
2020-10-23 00:37:05 +00:00
|
|
|
let mut fairings = std::mem::replace(&mut self.fairings, Fairings::new());
|
2020-10-22 10:27:04 +00:00
|
|
|
let rocket = fairings.attach(fairing, self).await;
|
|
|
|
(rocket, fairings)
|
|
|
|
};
|
|
|
|
|
2020-10-22 10:41:02 +00:00
|
|
|
// TODO: Reuse a single thread to run all attach fairings.
|
2020-10-22 10:27:04 +00:00
|
|
|
let (rocket, mut fairings) = match tokio::runtime::Handle::try_current() {
|
|
|
|
Ok(handle) => {
|
|
|
|
std::thread::spawn(move || {
|
2020-12-24 01:02:40 +00:00
|
|
|
let _e = handle.enter();
|
|
|
|
futures::executor::block_on(future)
|
2020-10-22 10:27:04 +00:00
|
|
|
}).join().unwrap()
|
|
|
|
}
|
|
|
|
Err(_) => {
|
|
|
|
std::thread::spawn(|| {
|
|
|
|
futures::executor::block_on(future)
|
|
|
|
}).join().unwrap()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
self = rocket;
|
|
|
|
|
|
|
|
// Note that `self.fairings` may now be non-empty! Move them to the end.
|
|
|
|
fairings.append(self.fairings);
|
|
|
|
self.fairings = fairings;
|
2017-04-20 20:43:01 +00:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-10-22 10:41:02 +00:00
|
|
|
/// Returns the active configuration.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
|
|
|
/// # #[macro_use] extern crate rocket;
|
|
|
|
/// use rocket::Rocket;
|
|
|
|
/// use rocket::fairing::AdHoc;
|
|
|
|
///
|
|
|
|
/// #[launch]
|
|
|
|
/// fn rocket() -> rocket::Rocket {
|
|
|
|
/// rocket::ignite()
|
|
|
|
/// .attach(AdHoc::on_launch("Config Printer", |rocket| {
|
|
|
|
/// println!("Rocket launch config: {:?}", rocket.config());
|
|
|
|
/// }))
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn config(&self) -> &Config {
|
|
|
|
&self.config
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the figment for configured provider.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// let rocket = rocket::ignite();
|
|
|
|
/// let figment = rocket.figment();
|
|
|
|
///
|
|
|
|
/// let port: u16 = figment.extract_inner("port").unwrap();
|
|
|
|
/// assert_eq!(port, rocket.config().port);
|
|
|
|
/// ```
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn figment(&self) -> &Figment {
|
|
|
|
&self.figment
|
|
|
|
}
|
|
|
|
|
2020-10-22 10:27:04 +00:00
|
|
|
/// Returns an iterator over all of the routes mounted on this instance of
|
2020-10-22 10:41:02 +00:00
|
|
|
/// Rocket. The order is unspecified.
|
2020-06-28 05:59:40 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
2020-10-22 10:27:04 +00:00
|
|
|
/// # #[macro_use] extern crate rocket;
|
|
|
|
/// use rocket::Rocket;
|
|
|
|
/// use rocket::fairing::AdHoc;
|
|
|
|
///
|
|
|
|
/// #[get("/hello")]
|
|
|
|
/// fn hello() -> &'static str {
|
|
|
|
/// "Hello, world!"
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// fn main() {
|
|
|
|
/// let mut rocket = rocket::ignite()
|
|
|
|
/// .mount("/", routes![hello])
|
|
|
|
/// .mount("/hi", routes![hello]);
|
|
|
|
///
|
|
|
|
/// for route in rocket.routes() {
|
|
|
|
/// match route.base() {
|
|
|
|
/// "/" => assert_eq!(route.uri.path(), "/hello"),
|
|
|
|
/// "/hi" => assert_eq!(route.uri.path(), "/hi/hello"),
|
|
|
|
/// _ => unreachable!("only /hello, /hi/hello are expected")
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// assert_eq!(rocket.routes().count(), 2);
|
|
|
|
/// }
|
2020-06-28 05:59:40 +00:00
|
|
|
/// ```
|
2020-10-22 10:27:04 +00:00
|
|
|
#[inline(always)]
|
|
|
|
pub fn routes(&self) -> impl Iterator<Item = &Route> + '_ {
|
|
|
|
self.router.routes()
|
2020-06-28 05:59:40 +00:00
|
|
|
}
|
|
|
|
|
2020-10-22 10:41:02 +00:00
|
|
|
/// Returns an iterator over all of the catchers registered on this instance
|
|
|
|
/// of Rocket. The order is unspecified.
|
2020-06-28 05:59:40 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
2020-10-22 10:41:02 +00:00
|
|
|
/// # #[macro_use] extern crate rocket;
|
|
|
|
/// use rocket::Rocket;
|
|
|
|
/// use rocket::fairing::AdHoc;
|
2020-06-28 05:59:40 +00:00
|
|
|
///
|
2020-10-22 10:41:02 +00:00
|
|
|
/// #[catch(404)] fn not_found() -> &'static str { "Nothing here, sorry!" }
|
|
|
|
/// #[catch(500)] fn just_500() -> &'static str { "Whoops!?" }
|
|
|
|
/// #[catch(default)] fn some_default() -> &'static str { "Everything else." }
|
2020-09-03 05:41:31 +00:00
|
|
|
///
|
2020-10-22 10:41:02 +00:00
|
|
|
/// fn main() {
|
|
|
|
/// let mut rocket = rocket::ignite()
|
|
|
|
/// .register(catchers![not_found, just_500, some_default]);
|
2020-09-03 05:41:31 +00:00
|
|
|
///
|
2020-10-22 10:41:02 +00:00
|
|
|
/// let mut codes: Vec<_> = rocket.catchers().map(|c| c.code).collect();
|
|
|
|
/// codes.sort();
|
2020-09-03 05:41:31 +00:00
|
|
|
///
|
2020-10-22 10:41:02 +00:00
|
|
|
/// assert_eq!(codes, vec![None, Some(404), Some(500)]);
|
|
|
|
/// }
|
2020-09-03 05:41:31 +00:00
|
|
|
/// ```
|
2020-10-22 10:27:04 +00:00
|
|
|
#[inline(always)]
|
2020-10-22 10:41:02 +00:00
|
|
|
pub fn catchers(&self) -> impl Iterator<Item = &Catcher> + '_ {
|
|
|
|
self.catchers.values().chain(self.default_catcher.as_ref())
|
2020-09-03 05:41:31 +00:00
|
|
|
}
|
|
|
|
|
2020-10-22 10:41:02 +00:00
|
|
|
/// Returns `Some` of the managed state value for the type `T` if it is
|
|
|
|
/// being managed by `self`. Otherwise, returns `None`.
|
2020-06-28 05:59:40 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
2020-10-22 10:41:02 +00:00
|
|
|
/// ```rust
|
|
|
|
/// #[derive(PartialEq, Debug)]
|
|
|
|
/// struct MyState(&'static str);
|
2020-06-28 05:59:40 +00:00
|
|
|
///
|
2020-10-22 10:41:02 +00:00
|
|
|
/// let rocket = rocket::ignite().manage(MyState("hello!"));
|
|
|
|
/// assert_eq!(rocket.state::<MyState>(), Some(&MyState("hello!")));
|
2020-06-28 05:59:40 +00:00
|
|
|
/// ```
|
2020-10-22 10:27:04 +00:00
|
|
|
#[inline(always)]
|
2020-10-22 10:41:02 +00:00
|
|
|
pub fn state<T: Send + Sync + 'static>(&self) -> Option<&T> {
|
|
|
|
self.managed_state.try_get()
|
2020-06-28 05:59:40 +00:00
|
|
|
}
|
|
|
|
|
2020-07-22 23:10:02 +00:00
|
|
|
/// Returns a handle which can be used to gracefully terminate this instance
|
|
|
|
/// of Rocket. In routes, use the [`Shutdown`] request guard.
|
2020-06-28 05:59:40 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
2020-10-22 10:27:04 +00:00
|
|
|
/// ```rust,no_run
|
2020-06-28 05:59:40 +00:00
|
|
|
/// # use std::{thread, time::Duration};
|
|
|
|
/// # rocket::async_test(async {
|
|
|
|
/// let mut rocket = rocket::ignite();
|
2020-10-22 10:27:04 +00:00
|
|
|
/// let handle = rocket.shutdown();
|
2020-06-28 05:59:40 +00:00
|
|
|
///
|
|
|
|
/// thread::spawn(move || {
|
|
|
|
/// thread::sleep(Duration::from_secs(10));
|
|
|
|
/// handle.shutdown();
|
|
|
|
/// });
|
|
|
|
///
|
|
|
|
/// // Shuts down after 10 seconds
|
|
|
|
/// let shutdown_result = rocket.launch().await;
|
|
|
|
/// assert!(shutdown_result.is_ok());
|
|
|
|
/// # });
|
|
|
|
/// ```
|
|
|
|
#[inline(always)]
|
2020-07-22 23:10:02 +00:00
|
|
|
pub fn shutdown(&self) -> Shutdown {
|
2020-06-28 05:59:40 +00:00
|
|
|
self.shutdown_handle.clone()
|
|
|
|
}
|
|
|
|
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
/// Perform "pre-launch" checks: verify:
|
|
|
|
/// * there are no routing colisionns
|
|
|
|
/// * there were no fairing failures
|
|
|
|
/// * a secret key, if needed, is securely configured
|
2020-09-03 05:41:31 +00:00
|
|
|
pub(crate) async fn prelaunch_check(&mut self) -> Result<(), Error> {
|
2020-06-28 05:59:40 +00:00
|
|
|
if let Err(e) = self.router.collisions() {
|
2020-09-03 05:41:31 +00:00
|
|
|
return Err(Error::new(ErrorKind::Collision(e)));
|
2020-06-28 05:59:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(failures) = self.fairings.failures() {
|
2020-09-03 05:41:31 +00:00
|
|
|
return Err(Error::new(ErrorKind::FailedFairings(failures.to_vec())))
|
2020-06-28 05:59:40 +00:00
|
|
|
}
|
|
|
|
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
#[cfg(feature = "secrets")]
|
|
|
|
if !self.config.secret_key.is_provided() {
|
|
|
|
let profile = self.figment.profile();
|
|
|
|
if profile != Config::DEBUG_PROFILE {
|
|
|
|
return Err(Error::new(ErrorKind::InsecureSecretKey(profile.clone())));
|
2021-03-10 10:13:50 +00:00
|
|
|
} else if self.config.secret_key.is_zero() {
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
self.config.secret_key = crate::config::SecretKey::generate()
|
|
|
|
.unwrap_or(crate::config::SecretKey::zero());
|
|
|
|
|
2021-03-10 10:13:50 +00:00
|
|
|
warn!("secrets enabled without a stable `secret_key`");
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
info_!("disable `secrets` feature or configure a `secret_key`");
|
|
|
|
info_!("this becomes an {} in non-debug profiles", Paint::red("error"));
|
|
|
|
|
|
|
|
if !self.config.secret_key.is_zero() {
|
|
|
|
warn_!("a random key has been generated for this launch");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-06-28 05:59:40 +00:00
|
|
|
Ok(())
|
2019-09-14 15:10:00 +00:00
|
|
|
}
|
2019-05-19 17:58:19 +00:00
|
|
|
|
2020-06-14 15:57:53 +00:00
|
|
|
/// Returns a `Future` that drives the server, listening for and dispatching
|
2020-06-14 15:57:51 +00:00
|
|
|
/// requests to mounted routes and catchers. The `Future` completes when the
|
2020-07-22 23:10:02 +00:00
|
|
|
/// server is shut down via [`Shutdown`], encounters a fatal error, or if
|
|
|
|
/// the the `ctrlc` configuration option is set, when `Ctrl+C` is pressed.
|
2020-06-14 15:57:51 +00:00
|
|
|
///
|
|
|
|
/// # Error
|
2020-06-14 15:57:53 +00:00
|
|
|
///
|
2020-06-14 15:57:51 +00:00
|
|
|
/// If there is a problem starting the application, an [`Error`] is
|
2020-07-22 23:10:02 +00:00
|
|
|
/// returned. Note that a value of type `Error` panics if dropped without
|
|
|
|
/// first being inspected. See the [`Error`] documentation for more
|
|
|
|
/// information.
|
|
|
|
///
|
2019-09-14 15:10:00 +00:00
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
2020-06-14 15:57:55 +00:00
|
|
|
/// #[rocket::main]
|
2019-12-11 00:34:23 +00:00
|
|
|
/// async fn main() {
|
2019-09-14 15:10:00 +00:00
|
|
|
/// # if false {
|
2020-06-14 15:57:55 +00:00
|
|
|
/// let result = rocket::ignite().launch().await;
|
2019-09-14 15:10:00 +00:00
|
|
|
/// assert!(result.is_ok());
|
|
|
|
/// # }
|
2019-12-11 00:34:23 +00:00
|
|
|
/// }
|
2019-09-14 15:10:00 +00:00
|
|
|
/// ```
|
2020-09-03 05:41:31 +00:00
|
|
|
pub async fn launch(mut self) -> Result<(), Error> {
|
2019-09-14 15:10:00 +00:00
|
|
|
use std::net::ToSocketAddrs;
|
2020-07-09 05:05:54 +00:00
|
|
|
use futures::future::Either;
|
2020-09-03 05:41:31 +00:00
|
|
|
use crate::http::private::bind_tcp;
|
2019-09-14 15:10:00 +00:00
|
|
|
|
2020-09-03 05:41:31 +00:00
|
|
|
self.prelaunch_check().await?;
|
2020-06-14 15:57:51 +00:00
|
|
|
|
2020-06-28 05:59:40 +00:00
|
|
|
let full_addr = format!("{}:{}", self.config.address, self.config.port);
|
2020-09-03 05:41:31 +00:00
|
|
|
let addr = full_addr.to_socket_addrs()
|
|
|
|
.map(|mut addrs| addrs.next().expect(">= 1 socket addr"))
|
|
|
|
.map_err(|e| Error::new(ErrorKind::Io(e)))?;
|
2019-09-14 15:10:00 +00:00
|
|
|
|
2020-07-09 05:05:54 +00:00
|
|
|
// If `ctrl-c` shutdown is enabled, we `select` on `the ctrl-c` signal
|
|
|
|
// and server. Otherwise, we only wait on the `server`, hence `pending`.
|
|
|
|
let shutdown_handle = self.shutdown_handle.clone();
|
2020-09-03 05:41:31 +00:00
|
|
|
let shutdown_signal = match self.config.ctrlc {
|
|
|
|
true => tokio::signal::ctrl_c().boxed(),
|
|
|
|
false => futures::future::pending().boxed(),
|
2020-07-09 05:05:54 +00:00
|
|
|
};
|
2019-09-14 15:10:00 +00:00
|
|
|
|
2020-09-03 05:41:31 +00:00
|
|
|
#[cfg(feature = "tls")]
|
2019-12-11 00:34:23 +00:00
|
|
|
let server = {
|
2021-03-09 02:18:15 +00:00
|
|
|
use crate::http::private::tls::bind_tls;
|
2019-09-14 15:10:00 +00:00
|
|
|
|
2020-09-03 05:41:31 +00:00
|
|
|
if let Some(tls_config) = &self.config.tls {
|
|
|
|
let (certs, key) = tls_config.to_readers().map_err(ErrorKind::Io)?;
|
|
|
|
let l = bind_tls(addr, certs, key).await.map_err(ErrorKind::Bind)?;
|
|
|
|
self.listen_on(l).boxed()
|
|
|
|
} else {
|
|
|
|
let l = bind_tcp(addr).await.map_err(ErrorKind::Bind)?;
|
|
|
|
self.listen_on(l).boxed()
|
2019-09-14 15:10:00 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-09-03 05:41:31 +00:00
|
|
|
#[cfg(not(feature = "tls"))]
|
|
|
|
let server = {
|
|
|
|
let l = bind_tcp(addr).await.map_err(ErrorKind::Bind)?;
|
|
|
|
self.listen_on(l).boxed()
|
|
|
|
};
|
|
|
|
|
2020-07-09 05:05:54 +00:00
|
|
|
match futures::future::select(shutdown_signal, server).await {
|
|
|
|
Either::Left((Ok(()), server)) => {
|
|
|
|
// Ctrl-was pressed. Signal shutdown, wait for the server.
|
|
|
|
shutdown_handle.shutdown();
|
|
|
|
server.await
|
|
|
|
}
|
|
|
|
Either::Left((Err(err), server)) => {
|
|
|
|
// Error setting up ctrl-c signal. Let the user know.
|
2020-09-03 05:41:31 +00:00
|
|
|
warn!("Failed to enable `ctrl-c` graceful signal shutdown.");
|
2020-07-09 05:05:54 +00:00
|
|
|
info_!("Error: {}", err);
|
|
|
|
server.await
|
|
|
|
}
|
|
|
|
// Server shut down before Ctrl-C; return the result.
|
|
|
|
Either::Right((result, _)) => result,
|
2019-08-25 02:19:11 +00:00
|
|
|
}
|
2019-08-18 02:00:32 +00:00
|
|
|
}
|
2020-06-28 05:59:40 +00:00
|
|
|
}
|