2020-10-23 00:37:05 +00:00
|
|
|
use std::io;
|
|
|
|
use std::sync::Arc;
|
2021-06-01 06:47:52 +00:00
|
|
|
use std::time::Duration;
|
2020-10-23 00:37:05 +00:00
|
|
|
|
2021-06-01 06:47:52 +00:00
|
|
|
use yansi::Paint;
|
|
|
|
use tokio::sync::oneshot;
|
2020-10-23 00:37:05 +00:00
|
|
|
use futures::stream::StreamExt;
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
use futures::future::{self, FutureExt, Future, TryFutureExt, BoxFuture};
|
2020-10-23 00:37:05 +00:00
|
|
|
|
2021-07-02 18:35:09 +00:00
|
|
|
use crate::{route, Rocket, Orbit, Request, Response, Data, Config};
|
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
|
|
|
use crate::form::Form;
|
2020-10-23 00:37:05 +00:00
|
|
|
use crate::outcome::Outcome;
|
|
|
|
use crate::error::{Error, ErrorKind};
|
2021-04-28 09:01:35 +00:00
|
|
|
use crate::ext::{AsyncReadExt, CancellableListener, CancellableIo};
|
2021-07-09 06:59:47 +00:00
|
|
|
use crate::request::ConnectionMeta;
|
2020-10-23 00:37:05 +00:00
|
|
|
|
2021-07-02 18:35:09 +00:00
|
|
|
use crate::http::{uri::Origin, hyper, Method, Status, Header};
|
2022-04-30 22:41:07 +00:00
|
|
|
use crate::http::private::{TcpListener, Listener, Connection, Incoming};
|
2020-10-23 00:37:05 +00:00
|
|
|
|
|
|
|
// A token returned to force the execution of one method before another.
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
pub(crate) struct RequestToken;
|
2020-10-23 00:37:05 +00:00
|
|
|
|
2021-03-15 09:20:48 +00:00
|
|
|
async fn handle<Fut, T, F>(name: Option<&str>, run: F) -> Option<T>
|
|
|
|
where F: FnOnce() -> Fut, Fut: Future<Output = T>,
|
|
|
|
{
|
|
|
|
use std::panic::AssertUnwindSafe;
|
|
|
|
|
|
|
|
macro_rules! panic_info {
|
|
|
|
($name:expr, $e:expr) => {{
|
|
|
|
match $name {
|
|
|
|
Some(name) => error_!("Handler {} panicked.", Paint::white(name)),
|
|
|
|
None => error_!("A handler panicked.")
|
|
|
|
};
|
|
|
|
|
|
|
|
info_!("This is an application bug.");
|
|
|
|
info_!("A panic in Rust must be treated as an exceptional event.");
|
|
|
|
info_!("Panicking is not a suitable error handling mechanism.");
|
|
|
|
info_!("Unwinding, the result of a panic, is an expensive operation.");
|
2021-06-26 19:05:04 +00:00
|
|
|
info_!("Panics will degrade application performance.");
|
2021-03-15 09:20:48 +00:00
|
|
|
info_!("Instead of panicking, return `Option` and/or `Result`.");
|
|
|
|
info_!("Values of either type can be returned directly from handlers.");
|
|
|
|
warn_!("A panic is treated as an internal server error.");
|
|
|
|
$e
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
|
|
|
let run = AssertUnwindSafe(run);
|
|
|
|
let fut = std::panic::catch_unwind(move || run())
|
|
|
|
.map_err(|e| panic_info!(name, e))
|
|
|
|
.ok()?;
|
|
|
|
|
|
|
|
AssertUnwindSafe(fut)
|
|
|
|
.catch_unwind()
|
|
|
|
.await
|
|
|
|
.map_err(|e| panic_info!(name, e))
|
|
|
|
.ok()
|
2021-03-06 09:37:36 +00:00
|
|
|
}
|
|
|
|
|
2020-10-23 00:37:05 +00:00
|
|
|
// This function tries to hide all of the Hyper-ness from Rocket. It essentially
|
|
|
|
// converts Hyper types into Rocket types, then calls the `dispatch` function,
|
|
|
|
// which knows nothing about Hyper. Because responding depends on the
|
|
|
|
// `HyperResponse` type, this function does the actual response processing.
|
|
|
|
async fn hyper_service_fn(
|
Introduce statically-enforced 'Rocket' phasing.
The core 'Rocket' type is parameterized: 'Rocket<P: Phase>', where
'Phase' is a newly introduced, sealed marker trait. The trait is
implemented by three new marker types representing the three launch
phases: 'Build', 'Ignite', and 'Orbit'. Progression through these three
phases, in order, is enforced, as are the invariants guaranteed by each
phase. In particular, an instance of 'Rocket' is guaranteed to be in its
final configuration after the 'Build' phase and represent a running
local or public server in the 'Orbit' phase. The 'Ignite' phase serves
as an intermediate, enabling inspection of a finalized but stationary
instance. Transition between phases validates the invariants required
by the transition.
All APIs have been adjusted appropriately, requiring either an instance
of 'Rocket' in a particular phase ('Rocket<Build>', 'Rocket<Ignite>', or
'Rocket<Orbit>') or operating generically on a 'Rocket<P>'.
Documentation is also updated and substantially improved to mention
required and guaranteed invariants.
Additionally, this commit makes the following relevant changes:
* 'Rocket::ignite()' is now a public interface.
* 'Rocket::{build,custom}' methods can no longer panic.
* 'Launch' fairings are now 'ignite' fairings.
* 'Liftoff' fairings are always run, even in local mode.
* All 'ignite' fairings run concurrently at ignition.
* Launch logging occurs on launch, not any point prior.
* Launch log messages have improved formatting.
* A new launch error kind, 'Config', was added.
* A 'fairing::Result' type alias was introduced.
* 'Shutdown::shutdown()' is now 'Shutdown::notify()'.
Some internal changes were also introduced:
* Fairing 'Info' name for 'Templates' is now 'Templating'.
* Shutdown is implemented using 'tokio::sync::Notify'.
* 'Client::debug()' is used nearly universally in tests.
Resolves #1154.
Resolves #1136.
2021-04-14 02:26:45 +00:00
|
|
|
rocket: Arc<Rocket<Orbit>>,
|
2021-07-09 06:59:47 +00:00
|
|
|
conn: ConnectionMeta,
|
2020-10-23 00:37:05 +00:00
|
|
|
hyp_req: hyper::Request<hyper::Body>,
|
|
|
|
) -> Result<hyper::Response<hyper::Body>, io::Error> {
|
|
|
|
// This future must return a hyper::Response, but the response body might
|
|
|
|
// borrow from the request. Instead, write the body in another future that
|
|
|
|
// sends the response metadata (and a body channel) prior.
|
|
|
|
let (tx, rx) = oneshot::channel();
|
|
|
|
|
|
|
|
tokio::spawn(async move {
|
2021-06-01 18:36:57 +00:00
|
|
|
// Convert a Hyper request into a Rocket request.
|
2021-06-08 09:13:02 +00:00
|
|
|
let (h_parts, mut h_body) = hyp_req.into_parts();
|
2021-07-09 06:59:47 +00:00
|
|
|
match Request::from_hyp(&rocket, &h_parts, Some(conn)) {
|
2021-06-26 19:05:04 +00:00
|
|
|
Ok(mut req) => {
|
|
|
|
// Convert into Rocket `Data`, dispatch request, write response.
|
|
|
|
let mut data = Data::from(&mut h_body);
|
|
|
|
let token = rocket.preprocess_request(&mut req, &mut data).await;
|
|
|
|
let response = rocket.dispatch(token, &mut req, data).await;
|
|
|
|
rocket.send_response(response, tx).await;
|
|
|
|
},
|
2020-10-23 00:37:05 +00:00
|
|
|
Err(e) => {
|
2021-06-26 19:05:04 +00:00
|
|
|
// TODO: We don't have a request to pass in, so we fabricate
|
|
|
|
// one. This is weird. Instead, let the user know that we failed
|
|
|
|
// to parse a request (a special handler?).
|
2020-10-23 00:37:05 +00:00
|
|
|
error!("Bad incoming request: {}", e);
|
2021-05-20 01:20:40 +00:00
|
|
|
let dummy = Request::new(&rocket, Method::Get, Origin::ROOT);
|
2021-06-26 19:05:04 +00:00
|
|
|
let response = rocket.handle_error(Status::BadRequest, &dummy).await;
|
|
|
|
rocket.send_response(response, tx).await;
|
2020-10-23 00:37:05 +00:00
|
|
|
}
|
2021-06-26 19:05:04 +00:00
|
|
|
}
|
2020-10-23 00:37:05 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// Receive the response written to `tx` by the task above.
|
2021-06-26 19:05:04 +00:00
|
|
|
rx.await.map_err(|e| io::Error::new(io::ErrorKind::BrokenPipe, e))
|
2020-10-23 00:37:05 +00:00
|
|
|
}
|
|
|
|
|
Introduce statically-enforced 'Rocket' phasing.
The core 'Rocket' type is parameterized: 'Rocket<P: Phase>', where
'Phase' is a newly introduced, sealed marker trait. The trait is
implemented by three new marker types representing the three launch
phases: 'Build', 'Ignite', and 'Orbit'. Progression through these three
phases, in order, is enforced, as are the invariants guaranteed by each
phase. In particular, an instance of 'Rocket' is guaranteed to be in its
final configuration after the 'Build' phase and represent a running
local or public server in the 'Orbit' phase. The 'Ignite' phase serves
as an intermediate, enabling inspection of a finalized but stationary
instance. Transition between phases validates the invariants required
by the transition.
All APIs have been adjusted appropriately, requiring either an instance
of 'Rocket' in a particular phase ('Rocket<Build>', 'Rocket<Ignite>', or
'Rocket<Orbit>') or operating generically on a 'Rocket<P>'.
Documentation is also updated and substantially improved to mention
required and guaranteed invariants.
Additionally, this commit makes the following relevant changes:
* 'Rocket::ignite()' is now a public interface.
* 'Rocket::{build,custom}' methods can no longer panic.
* 'Launch' fairings are now 'ignite' fairings.
* 'Liftoff' fairings are always run, even in local mode.
* All 'ignite' fairings run concurrently at ignition.
* Launch logging occurs on launch, not any point prior.
* Launch log messages have improved formatting.
* A new launch error kind, 'Config', was added.
* A 'fairing::Result' type alias was introduced.
* 'Shutdown::shutdown()' is now 'Shutdown::notify()'.
Some internal changes were also introduced:
* Fairing 'Info' name for 'Templates' is now 'Templating'.
* Shutdown is implemented using 'tokio::sync::Notify'.
* 'Client::debug()' is used nearly universally in tests.
Resolves #1154.
Resolves #1136.
2021-04-14 02:26:45 +00:00
|
|
|
impl Rocket<Orbit> {
|
2021-06-26 19:05:04 +00:00
|
|
|
/// Wrapper around `_send_response` to log a success or failure.
|
2020-10-23 00:37:05 +00:00
|
|
|
#[inline]
|
|
|
|
async fn send_response(
|
|
|
|
&self,
|
|
|
|
response: Response<'_>,
|
|
|
|
tx: oneshot::Sender<hyper::Response<hyper::Body>>,
|
|
|
|
) {
|
2021-06-26 19:05:04 +00:00
|
|
|
let remote_hungup = |e: &io::Error| match e.kind() {
|
|
|
|
| io::ErrorKind::BrokenPipe
|
|
|
|
| io::ErrorKind::ConnectionReset
|
|
|
|
| io::ErrorKind::ConnectionAborted => true,
|
|
|
|
_ => false,
|
|
|
|
};
|
|
|
|
|
|
|
|
match self._send_response(response, tx).await {
|
2020-10-23 00:37:05 +00:00
|
|
|
Ok(()) => info_!("{}", Paint::green("Response succeeded.")),
|
2021-06-26 19:05:04 +00:00
|
|
|
Err(e) if remote_hungup(&e) => warn_!("Remote left: {}.", e),
|
|
|
|
Err(e) => warn_!("Failed to write response: {}.", e),
|
2020-10-23 00:37:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Attempts to create a hyper response from `response` and send it to `tx`.
|
|
|
|
#[inline]
|
2021-06-26 19:05:04 +00:00
|
|
|
async fn _send_response(
|
2020-10-23 00:37:05 +00:00
|
|
|
&self,
|
|
|
|
mut response: Response<'_>,
|
|
|
|
tx: oneshot::Sender<hyper::Response<hyper::Body>>,
|
|
|
|
) -> io::Result<()> {
|
2021-06-26 19:05:04 +00:00
|
|
|
let mut hyp_res = hyper::Response::builder();
|
2020-10-23 00:37:05 +00:00
|
|
|
|
2021-06-26 19:05:04 +00:00
|
|
|
hyp_res = hyp_res.status(response.status().code);
|
2020-10-23 00:37:05 +00:00
|
|
|
for header in response.headers().iter() {
|
|
|
|
let name = header.name.as_str();
|
|
|
|
let value = header.value.as_bytes();
|
|
|
|
hyp_res = hyp_res.header(name, value);
|
|
|
|
}
|
|
|
|
|
2021-04-28 08:51:51 +00:00
|
|
|
let body = response.body_mut();
|
|
|
|
if let Some(n) = body.size().await {
|
|
|
|
hyp_res = hyp_res.header(hyper::header::CONTENT_LENGTH, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
let (mut sender, hyp_body) = hyper::Body::channel();
|
2021-06-26 19:05:04 +00:00
|
|
|
let hyp_response = hyp_res.body(hyp_body)
|
|
|
|
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
|
|
|
|
|
|
|
tx.send(hyp_response).map_err(|_| {
|
|
|
|
let msg = "client disconnect before response started";
|
|
|
|
io::Error::new(io::ErrorKind::BrokenPipe, msg)
|
|
|
|
})?;
|
2021-04-28 08:51:51 +00:00
|
|
|
|
2021-06-26 19:05:04 +00:00
|
|
|
let max_chunk_size = body.max_chunk_size();
|
2021-04-28 08:51:51 +00:00
|
|
|
let mut stream = body.into_bytes_stream(max_chunk_size);
|
|
|
|
while let Some(next) = stream.next().await {
|
|
|
|
sender.send_data(next?).await
|
2021-06-26 19:05:04 +00:00
|
|
|
.map_err(|e| io::Error::new(io::ErrorKind::BrokenPipe, e))?;
|
2021-04-28 08:51:51 +00:00
|
|
|
}
|
2020-10-23 00:37:05 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Preprocess the request for Rocket things. Currently, this means:
|
|
|
|
///
|
|
|
|
/// * Rewriting the method in the request if _method form field exists.
|
|
|
|
/// * Run the request fairings.
|
|
|
|
///
|
|
|
|
/// Keep this in-sync with derive_form when preprocessing form fields.
|
|
|
|
pub(crate) async fn preprocess_request(
|
|
|
|
&self,
|
|
|
|
req: &mut Request<'_>,
|
2021-06-08 09:13:02 +00:00
|
|
|
data: &mut Data<'_>
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
) -> RequestToken {
|
2020-10-23 00:37:05 +00:00
|
|
|
// Check if this is a form and if the form contains the special _method
|
|
|
|
// field which we use to reinterpret the request's method.
|
|
|
|
let (min_len, max_len) = ("_method=get".len(), "_method=delete".len());
|
|
|
|
let peek_buffer = data.peek(max_len).await;
|
|
|
|
let is_form = req.content_type().map_or(false, |ct| ct.is_form());
|
|
|
|
|
|
|
|
if is_form && req.method() == Method::Post && peek_buffer.len() >= min_len {
|
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 method = std::str::from_utf8(peek_buffer).ok()
|
|
|
|
.and_then(|raw_form| Form::values(raw_form).next())
|
|
|
|
.filter(|field| field.name == "_method")
|
|
|
|
.and_then(|field| field.value.parse().ok());
|
|
|
|
|
|
|
|
if let Some(method) = method {
|
|
|
|
req._set_method(method);
|
2020-10-23 00:37:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run request fairings.
|
|
|
|
self.fairings.handle_request(req, data).await;
|
|
|
|
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
RequestToken
|
2020-10-23 00:37:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub(crate) async fn dispatch<'s, 'r: 's>(
|
|
|
|
&'s self,
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
_token: RequestToken,
|
2020-10-23 00:37:05 +00:00
|
|
|
request: &'r Request<'s>,
|
2021-06-08 09:13:02 +00:00
|
|
|
data: Data<'r>
|
2020-10-23 00:37:05 +00:00
|
|
|
) -> Response<'r> {
|
|
|
|
info!("{}:", request);
|
|
|
|
|
|
|
|
// Remember if the request is `HEAD` for later body stripping.
|
|
|
|
let was_head_request = request.method() == Method::Head;
|
|
|
|
|
|
|
|
// Route the request and run the user's handlers.
|
|
|
|
let mut response = self.route_and_process(request, data).await;
|
|
|
|
|
|
|
|
// Add a default 'Server' header if it isn't already there.
|
|
|
|
// TODO: If removing Hyper, write out `Date` header too.
|
2021-06-09 06:00:36 +00:00
|
|
|
if let Some(ident) = request.rocket().config.ident.as_str() {
|
|
|
|
if !response.headers().contains("Server") {
|
|
|
|
response.set_header(Header::new("Server", ident));
|
|
|
|
}
|
2020-10-23 00:37:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Run the response fairings.
|
|
|
|
self.fairings.handle_response(request, &mut response).await;
|
|
|
|
|
|
|
|
// Strip the body if this is a `HEAD` request.
|
|
|
|
if was_head_request {
|
|
|
|
response.strip_body();
|
|
|
|
}
|
|
|
|
|
|
|
|
response
|
|
|
|
}
|
|
|
|
|
2021-03-11 00:31:32 +00:00
|
|
|
async fn route_and_process<'s, 'r: 's>(
|
2020-10-23 00:37:05 +00:00
|
|
|
&'s self,
|
|
|
|
request: &'r Request<'s>,
|
2021-06-08 09:13:02 +00:00
|
|
|
data: Data<'r>
|
2021-03-11 00:31:32 +00:00
|
|
|
) -> Response<'r> {
|
|
|
|
let mut response = match self.route(request, data).await {
|
|
|
|
Outcome::Success(response) => response,
|
|
|
|
Outcome::Forward(data) if request.method() == Method::Head => {
|
|
|
|
info_!("Autohandling {} request.", Paint::default("HEAD").bold());
|
|
|
|
|
|
|
|
// Dispatch the request again with Method `GET`.
|
|
|
|
request._set_method(Method::Get);
|
|
|
|
match self.route(request, data).await {
|
|
|
|
Outcome::Success(response) => response,
|
|
|
|
Outcome::Failure(status) => self.handle_error(status, request).await,
|
|
|
|
Outcome::Forward(_) => self.handle_error(Status::NotFound, request).await,
|
2020-10-23 00:37:05 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-11 00:31:32 +00:00
|
|
|
Outcome::Forward(_) => self.handle_error(Status::NotFound, request).await,
|
|
|
|
Outcome::Failure(status) => self.handle_error(status, request).await,
|
|
|
|
};
|
2020-10-23 00:37:05 +00:00
|
|
|
|
2021-03-11 00:31:32 +00:00
|
|
|
// Set the cookies. Note that error responses will only include cookies
|
|
|
|
// set by the error handler. See `handle_error` for more.
|
|
|
|
let delta_jar = request.cookies().take_delta_jar();
|
|
|
|
for cookie in delta_jar.delta() {
|
|
|
|
response.adjoin_header(cookie);
|
2020-10-23 00:37:05 +00:00
|
|
|
}
|
2021-03-11 00:31:32 +00:00
|
|
|
|
|
|
|
response
|
2020-10-23 00:37:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Tries to find a `Responder` for a given `request`. It does this by
|
|
|
|
/// routing the request and calling the handler for each matching route
|
|
|
|
/// until one of the handlers returns success or failure, or there are no
|
|
|
|
/// additional routes to try (forward). The corresponding outcome for each
|
|
|
|
/// condition is returned.
|
|
|
|
#[inline]
|
2021-03-11 00:31:32 +00:00
|
|
|
async fn route<'s, 'r: 's>(
|
2020-10-23 00:37:05 +00:00
|
|
|
&'s self,
|
|
|
|
request: &'r Request<'s>,
|
2021-06-08 09:13:02 +00:00
|
|
|
mut data: Data<'r>,
|
2021-04-14 01:58:05 +00:00
|
|
|
) -> route::Outcome<'r> {
|
2021-03-11 00:31:32 +00:00
|
|
|
// Go through the list of matching routes until we fail or succeed.
|
2021-03-19 10:41:52 +00:00
|
|
|
for route in self.router.route(request) {
|
2021-03-11 00:31:32 +00:00
|
|
|
// Retrieve and set the requests parameters.
|
|
|
|
info_!("Matched: {}", route);
|
|
|
|
request.set_route(route);
|
|
|
|
|
2021-03-15 09:20:48 +00:00
|
|
|
let name = route.name.as_deref();
|
|
|
|
let outcome = handle(name, || route.handler.handle(request, data)).await
|
2021-06-30 20:36:23 +00:00
|
|
|
.unwrap_or(Outcome::Failure(Status::InternalServerError));
|
2021-03-11 00:31:32 +00:00
|
|
|
|
|
|
|
// Check if the request processing completed (Some) or if the
|
|
|
|
// request needs to be forwarded. If it does, continue the loop
|
|
|
|
// (None) to try again.
|
|
|
|
info_!("{} {}", Paint::default("Outcome:").bold(), outcome);
|
|
|
|
match outcome {
|
|
|
|
o@Outcome::Success(_) | o@Outcome::Failure(_) => return o,
|
|
|
|
Outcome::Forward(unused_data) => data = unused_data,
|
2020-10-23 00:37:05 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-11 00:31:32 +00:00
|
|
|
|
|
|
|
error_!("No matching routes for {}.", request);
|
|
|
|
Outcome::Forward(data)
|
2020-10-23 00:37:05 +00:00
|
|
|
}
|
|
|
|
|
2021-03-06 09:37:36 +00:00
|
|
|
/// Invokes the handler with `req` for catcher with status `status`.
|
|
|
|
///
|
|
|
|
/// In order of preference, invoked handler is:
|
|
|
|
/// * the user's registered handler for `status`
|
|
|
|
/// * the user's registered `default` handler
|
|
|
|
/// * Rocket's default handler for `status`
|
|
|
|
///
|
|
|
|
/// Return `Ok(result)` if the handler succeeded. Returns `Ok(Some(Status))`
|
|
|
|
/// if the handler ran to completion but failed. Returns `Ok(None)` if the
|
|
|
|
/// handler panicked while executing.
|
|
|
|
async fn invoke_catcher<'s, 'r: 's>(
|
2020-10-23 00:37:05 +00:00
|
|
|
&'s self,
|
|
|
|
status: Status,
|
|
|
|
req: &'r Request<'s>
|
2021-03-06 09:37:36 +00:00
|
|
|
) -> Result<Response<'r>, Option<Status>> {
|
|
|
|
// For now, we reset the delta state to prevent any modifications
|
|
|
|
// from earlier, unsuccessful paths from being reflected in error
|
|
|
|
// response. We may wish to relax this in the future.
|
|
|
|
req.cookies().reset_delta();
|
|
|
|
|
2021-03-26 04:36:00 +00:00
|
|
|
if let Some(catcher) = self.router.catch(status, req) {
|
2021-03-06 09:37:36 +00:00
|
|
|
warn_!("Responding with registered {} catcher.", catcher);
|
2021-03-15 09:27:53 +00:00
|
|
|
let name = catcher.name.as_deref();
|
|
|
|
handle(name, || catcher.handler.handle(status, req)).await
|
2021-03-06 09:37:36 +00:00
|
|
|
.map(|result| result.map_err(Some))
|
2021-03-15 09:20:48 +00:00
|
|
|
.unwrap_or_else(|| Err(None))
|
2021-03-06 09:37:36 +00:00
|
|
|
} else {
|
|
|
|
let code = Paint::blue(status.code).bold();
|
|
|
|
warn_!("No {} catcher registered. Using Rocket default.", code);
|
2021-04-14 01:58:05 +00:00
|
|
|
Ok(crate::catcher::default_handler(status, req))
|
2021-03-06 09:37:36 +00:00
|
|
|
}
|
|
|
|
}
|
2020-10-23 00:37:05 +00:00
|
|
|
|
2021-03-06 09:37:36 +00:00
|
|
|
// Invokes the catcher for `status`. Returns the response on success.
|
|
|
|
//
|
|
|
|
// On catcher failure, the 500 error catcher is attempted. If _that_ fails,
|
|
|
|
// the (infallible) default 500 error cather is used.
|
|
|
|
pub(crate) async fn handle_error<'s, 'r: 's>(
|
|
|
|
&'s self,
|
|
|
|
mut status: Status,
|
|
|
|
req: &'r Request<'s>
|
|
|
|
) -> Response<'r> {
|
|
|
|
// Dispatch to the `status` catcher.
|
|
|
|
if let Ok(r) = self.invoke_catcher(status, req).await {
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If it fails and it's not a 500, try the 500 catcher.
|
|
|
|
if status != Status::InternalServerError {
|
|
|
|
error_!("Catcher failed. Attemping 500 error catcher.");
|
|
|
|
status = Status::InternalServerError;
|
|
|
|
if let Ok(r) = self.invoke_catcher(status, req).await {
|
|
|
|
return r;
|
2020-10-23 00:37:05 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-06 09:37:36 +00:00
|
|
|
|
|
|
|
// If it failed again or if it was already a 500, use Rocket's default.
|
|
|
|
error_!("{} catcher failed. Using Rocket default 500.", status.code);
|
2021-04-14 01:58:05 +00:00
|
|
|
crate::catcher::default_handler(Status::InternalServerError, req)
|
2020-10-23 00:37:05 +00:00
|
|
|
}
|
|
|
|
|
Introduce statically-enforced 'Rocket' phasing.
The core 'Rocket' type is parameterized: 'Rocket<P: Phase>', where
'Phase' is a newly introduced, sealed marker trait. The trait is
implemented by three new marker types representing the three launch
phases: 'Build', 'Ignite', and 'Orbit'. Progression through these three
phases, in order, is enforced, as are the invariants guaranteed by each
phase. In particular, an instance of 'Rocket' is guaranteed to be in its
final configuration after the 'Build' phase and represent a running
local or public server in the 'Orbit' phase. The 'Ignite' phase serves
as an intermediate, enabling inspection of a finalized but stationary
instance. Transition between phases validates the invariants required
by the transition.
All APIs have been adjusted appropriately, requiring either an instance
of 'Rocket' in a particular phase ('Rocket<Build>', 'Rocket<Ignite>', or
'Rocket<Orbit>') or operating generically on a 'Rocket<P>'.
Documentation is also updated and substantially improved to mention
required and guaranteed invariants.
Additionally, this commit makes the following relevant changes:
* 'Rocket::ignite()' is now a public interface.
* 'Rocket::{build,custom}' methods can no longer panic.
* 'Launch' fairings are now 'ignite' fairings.
* 'Liftoff' fairings are always run, even in local mode.
* All 'ignite' fairings run concurrently at ignition.
* Launch logging occurs on launch, not any point prior.
* Launch log messages have improved formatting.
* A new launch error kind, 'Config', was added.
* A 'fairing::Result' type alias was introduced.
* 'Shutdown::shutdown()' is now 'Shutdown::notify()'.
Some internal changes were also introduced:
* Fairing 'Info' name for 'Templates' is now 'Templating'.
* Shutdown is implemented using 'tokio::sync::Notify'.
* 'Client::debug()' is used nearly universally in tests.
Resolves #1154.
Resolves #1136.
2021-04-14 02:26:45 +00:00
|
|
|
pub(crate) async fn default_tcp_http_server<C>(mut self, ready: C) -> Result<(), Error>
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
where C: for<'a> Fn(&'a Self) -> BoxFuture<'a, ()>
|
2020-10-23 00:37:05 +00:00
|
|
|
{
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
use std::net::ToSocketAddrs;
|
|
|
|
|
|
|
|
// Determine the address we're going to serve on.
|
|
|
|
let addr = format!("{}:{}", self.config.address, self.config.port);
|
|
|
|
let mut addr = addr.to_socket_addrs()
|
|
|
|
.map(|mut addrs| addrs.next().expect(">= 1 socket addr"))
|
|
|
|
.map_err(|e| Error::new(ErrorKind::Io(e)))?;
|
|
|
|
|
|
|
|
#[cfg(feature = "tls")]
|
2021-07-09 06:59:47 +00:00
|
|
|
if self.config.tls_enabled() {
|
|
|
|
if let Some(ref config) = self.config.tls {
|
|
|
|
use crate::http::tls::TlsListener;
|
|
|
|
|
|
|
|
let conf = config.to_native_config().map_err(ErrorKind::Io)?;
|
|
|
|
let l = TlsListener::bind(addr, conf).await.map_err(ErrorKind::Bind)?;
|
|
|
|
addr = l.local_addr().unwrap_or(addr);
|
|
|
|
self.config.address = addr.ip();
|
|
|
|
self.config.port = addr.port();
|
|
|
|
ready(&mut self).await;
|
|
|
|
return self.http_server(l).await;
|
|
|
|
}
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
}
|
2020-12-17 09:29:59 +00:00
|
|
|
|
2022-04-30 22:41:07 +00:00
|
|
|
let l = TcpListener::bind(addr).await.map_err(ErrorKind::Bind)?;
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
addr = l.local_addr().unwrap_or(addr);
|
|
|
|
self.config.address = addr.ip();
|
|
|
|
self.config.port = addr.port();
|
|
|
|
ready(&mut self).await;
|
|
|
|
self.http_server(l).await
|
|
|
|
}
|
2020-10-23 00:37:05 +00:00
|
|
|
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
// TODO.async: Solidify the Listener APIs and make this function public
|
Introduce statically-enforced 'Rocket' phasing.
The core 'Rocket' type is parameterized: 'Rocket<P: Phase>', where
'Phase' is a newly introduced, sealed marker trait. The trait is
implemented by three new marker types representing the three launch
phases: 'Build', 'Ignite', and 'Orbit'. Progression through these three
phases, in order, is enforced, as are the invariants guaranteed by each
phase. In particular, an instance of 'Rocket' is guaranteed to be in its
final configuration after the 'Build' phase and represent a running
local or public server in the 'Orbit' phase. The 'Ignite' phase serves
as an intermediate, enabling inspection of a finalized but stationary
instance. Transition between phases validates the invariants required
by the transition.
All APIs have been adjusted appropriately, requiring either an instance
of 'Rocket' in a particular phase ('Rocket<Build>', 'Rocket<Ignite>', or
'Rocket<Orbit>') or operating generically on a 'Rocket<P>'.
Documentation is also updated and substantially improved to mention
required and guaranteed invariants.
Additionally, this commit makes the following relevant changes:
* 'Rocket::ignite()' is now a public interface.
* 'Rocket::{build,custom}' methods can no longer panic.
* 'Launch' fairings are now 'ignite' fairings.
* 'Liftoff' fairings are always run, even in local mode.
* All 'ignite' fairings run concurrently at ignition.
* Launch logging occurs on launch, not any point prior.
* Launch log messages have improved formatting.
* A new launch error kind, 'Config', was added.
* A 'fairing::Result' type alias was introduced.
* 'Shutdown::shutdown()' is now 'Shutdown::notify()'.
Some internal changes were also introduced:
* Fairing 'Info' name for 'Templates' is now 'Templating'.
* Shutdown is implemented using 'tokio::sync::Notify'.
* 'Client::debug()' is used nearly universally in tests.
Resolves #1154.
Resolves #1136.
2021-04-14 02:26:45 +00:00
|
|
|
pub(crate) async fn http_server<L>(self, listener: L) -> Result<(), Error>
|
2021-04-28 09:01:35 +00:00
|
|
|
where L: Listener + Send, <L as Listener>::Connection: Send + Unpin + 'static
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
{
|
2021-07-02 18:35:09 +00:00
|
|
|
// Emit a warning if we're not running inside of Rocket's async runtime.
|
|
|
|
if self.config.profile == Config::DEBUG_PROFILE {
|
|
|
|
tokio::task::spawn_blocking(|| {
|
|
|
|
let this = std::thread::current();
|
|
|
|
if !this.name().map_or(false, |s| s.starts_with("rocket-worker")) {
|
|
|
|
warn!("Rocket is executing inside of a custom runtime.");
|
|
|
|
info_!("Rocket's runtime is enabled via `#[rocket::main]` or `#[launch]`.");
|
|
|
|
info_!("Forced shutdown is disabled. Runtime settings may be suboptimal.");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-04-28 09:01:35 +00:00
|
|
|
// Set up cancellable I/O from the given listener. Shutdown occurs when
|
|
|
|
// `Shutdown` (`TripWire`) resolves. This can occur directly through a
|
|
|
|
// notification or indirectly through an external signal which, when
|
|
|
|
// received, results in triggering the notify.
|
|
|
|
let shutdown = self.shutdown();
|
2021-06-01 06:47:52 +00:00
|
|
|
let sig_stream = self.config.shutdown.signal_stream();
|
|
|
|
let force_shutdown = self.config.shutdown.force;
|
2021-04-28 09:01:35 +00:00
|
|
|
let grace = self.config.shutdown.grace as u64;
|
2021-04-30 02:19:07 +00:00
|
|
|
let mercy = self.config.shutdown.mercy as u64;
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
|
2021-07-02 18:35:09 +00:00
|
|
|
// Start a task that listens for external signals and notifies shutdown.
|
|
|
|
if let Some(mut stream) = sig_stream {
|
|
|
|
let shutdown = shutdown.clone();
|
|
|
|
tokio::spawn(async move {
|
|
|
|
while let Some(sig) = stream.next().await {
|
|
|
|
if shutdown.0.tripped() {
|
|
|
|
warn!("Received {}. Shutdown already in progress.", sig);
|
|
|
|
} else {
|
|
|
|
warn!("Received {}. Requesting shutdown.", sig);
|
|
|
|
}
|
|
|
|
|
|
|
|
shutdown.0.trip();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-02-23 19:11:28 +00:00
|
|
|
// Save the keep-alive value for later use; we're about to move `self`.
|
|
|
|
let keep_alive = self.config.keep_alive;
|
|
|
|
|
2021-07-02 18:35:09 +00:00
|
|
|
// Create the Hyper `Service`.
|
2020-10-23 00:37:05 +00:00
|
|
|
let rocket = Arc::new(self);
|
2021-04-28 09:01:35 +00:00
|
|
|
let service_fn = move |conn: &CancellableIo<_, L::Connection>| {
|
2020-10-23 00:37:05 +00:00
|
|
|
let rocket = rocket.clone();
|
2021-07-09 06:59:47 +00:00
|
|
|
let connection = ConnectionMeta {
|
|
|
|
remote: conn.peer_address(),
|
2022-02-22 22:01:25 +00:00
|
|
|
client_certificates: conn.peer_certificates().map(|certs| Arc::new(certs.to_vec())),
|
2021-07-09 06:59:47 +00:00
|
|
|
};
|
|
|
|
|
2020-10-23 00:37:05 +00:00
|
|
|
async move {
|
2021-07-09 06:59:47 +00:00
|
|
|
Ok::<_, std::convert::Infallible>(hyper::service::service_fn(move |req| {
|
|
|
|
hyper_service_fn(rocket.clone(), connection.clone(), req)
|
2020-10-23 00:37:05 +00:00
|
|
|
}))
|
|
|
|
}
|
2021-04-28 09:01:35 +00:00
|
|
|
};
|
2020-10-23 00:37:05 +00:00
|
|
|
|
|
|
|
// NOTE: `hyper` uses `tokio::spawn()` as the default executor.
|
2021-04-30 02:19:07 +00:00
|
|
|
let listener = CancellableListener::new(shutdown.clone(), listener, grace, mercy);
|
2022-04-28 02:30:17 +00:00
|
|
|
let builder = hyper::Server::builder(Incoming::new(listener).nodelay(true));
|
2022-02-23 19:11:28 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "http2")]
|
|
|
|
let builder = builder.http2_keep_alive_interval(match keep_alive {
|
|
|
|
0 => None,
|
|
|
|
n => Some(Duration::from_secs(n as u64))
|
|
|
|
});
|
|
|
|
|
|
|
|
let server = builder
|
|
|
|
.http1_keepalive(keep_alive != 0)
|
2021-06-09 00:51:39 +00:00
|
|
|
.http1_preserve_header_case(true)
|
2021-07-09 06:59:47 +00:00
|
|
|
.serve(hyper::service::make_service_fn(service_fn))
|
2021-04-28 09:01:35 +00:00
|
|
|
.with_graceful_shutdown(shutdown.clone())
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
.map_err(|e| Error::new(ErrorKind::Runtime(Box::new(e))));
|
|
|
|
|
2021-06-01 06:47:52 +00:00
|
|
|
// Wait for a shutdown notification or for the server to somehow fail.
|
|
|
|
tokio::pin!(server);
|
|
|
|
match future::select(shutdown, server).await {
|
2021-04-28 09:01:35 +00:00
|
|
|
future::Either::Left((_, server)) => {
|
2021-06-01 06:47:52 +00:00
|
|
|
// If a task has some runaway I/O, like an infinite loop, the
|
|
|
|
// runtime will block indefinitely when it is dropped. To
|
|
|
|
// subvert, we start a ticking process-exit time bomb here.
|
|
|
|
if force_shutdown {
|
|
|
|
// Only a worker thread will have the specified thread name.
|
|
|
|
tokio::task::spawn_blocking(move || {
|
|
|
|
// We only hit our `exit()` if the process doesn't
|
|
|
|
// otherwise exit since this `spawn()` won't block.
|
2021-07-02 18:35:09 +00:00
|
|
|
let this = std::thread::current();
|
|
|
|
std::thread::spawn(move || {
|
|
|
|
std::thread::sleep(Duration::from_secs(grace + mercy));
|
|
|
|
std::thread::sleep(Duration::from_millis(500));
|
|
|
|
if this.name().map_or(false, |s| s.starts_with("rocket-worker")) {
|
2021-06-01 06:47:52 +00:00
|
|
|
error!("Server failed to shutdown cooperatively. Terminating.");
|
|
|
|
std::process::exit(1);
|
|
|
|
} else {
|
|
|
|
warn!("Server failed to shutdown cooperatively.");
|
|
|
|
warn_!("Server is executing inside of a custom runtime.");
|
|
|
|
info_!("Rocket's runtime is `#[rocket::main]` or `#[launch]`.");
|
|
|
|
warn_!("Refusing to terminate runaway custom runtime.");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
info!("Received shutdown request. Waiting for pending I/O...");
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
server.await
|
|
|
|
}
|
|
|
|
future::Either::Right((result, _)) => result,
|
|
|
|
}
|
2020-10-23 00:37:05 +00:00
|
|
|
}
|
|
|
|
}
|