Drop 'Data' after sending a response, not before.

This allows responses to be sent to the client even when data is only
partially read, significantly improving the experience for the client
from one with a "connection closed" error to one with a proper response.
The consequence is a lifetime in 'Data'.

Though other non-lifetime-introducing solutions exist, the introduction
of a lifetime to 'Data' is a longstanding desire as it prevents
smuggling 'Data' into a longer-lived context. Use of 'Data' in that
context was unspecified with various runtime consequences. The addition
of a lifetime bound by the request prevents this error statically.

In summary, the changes are:
  * Clients receive responses even when data isn't fully read.
  * 'Data' becomes 'Data<'r>'. 'FromData' changes accordingly.
  * Route 'Outcome's are strictly tied to the request lifetime.

Tangentially, the invalid length form field validation error message has
improved to format length in byte units if it exceeds 1024.
This commit is contained in:
Sergio Benitez 2021-06-08 02:13:02 -07:00
parent 7595450adc
commit 4c6562cd29
41 changed files with 179 additions and 172 deletions

View File

@ -6,7 +6,7 @@ use rocket::{route, config, Request, Data, Route, Config};
use rocket::http::{Method, RawStr, ContentType, Accept, Status};
use rocket::local::blocking::{Client, LocalRequest};
fn dummy_handler<'r>(req: &'r Request, _: Data) -> route::BoxFuture<'r> {
fn dummy_handler<'r>(req: &'r Request, _: Data<'r>) -> route::BoxFuture<'r> {
route::Outcome::from(req, ()).pin()
}

View File

@ -65,7 +65,7 @@ impl Fairing for TemplateFairing {
}
#[cfg(debug_assertions)]
async fn on_request(&self, req: &mut rocket::Request<'_>, _data: &mut rocket::Data) {
async fn on_request(&self, req: &mut rocket::Request<'_>, _data: &mut rocket::Data<'_>) {
let cm = req.rocket().state::<ContextManager>()
.expect("Template ContextManager registered in on_ignite");

View File

@ -64,10 +64,10 @@ pub fn _catch(
/// Rocket code generated proxy static conversion implementations.
impl #user_catcher_fn_name {
fn into_info(self) -> #_catcher::StaticInfo {
fn monomorphized_function<'_b>(
fn monomorphized_function<'__r>(
#__status: #Status,
#__req: &'_b #Request<'_>
) -> #_catcher::BoxFuture<'_b> {
#__req: &'__r #Request<'_>
) -> #_catcher::BoxFuture<'__r> {
#_Box::pin(async move {
let __response = #catcher_response;
#Response::build()

View File

@ -331,10 +331,10 @@ fn codegen_route(route: Route) -> Result<TokenStream> {
impl #handler_fn_name {
#[allow(non_snake_case, unreachable_patterns, unreachable_code)]
fn into_info(self) -> #_route::StaticInfo {
fn monomorphized_function<'_b>(
#__req: &'_b #Request<'_>,
#__data: #Data
) -> #_route::BoxFuture<'_b> {
fn monomorphized_function<'__r>(
#__req: &'__r #Request<'_>,
#__data: #Data<'__r>
) -> #_route::BoxFuture<'__r> {
#_Box::pin(async move {
#(#request_guards)*
#(#param_guards)*

View File

@ -19,7 +19,7 @@ struct Simple<'r>(&'r str);
impl<'r> FromData<'r> for Simple<'r> {
type Error = std::io::Error;
async fn from_data(req: &'r Request<'_>, data: Data) -> data::Outcome<Self, Self::Error> {
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> data::Outcome<'r, Self> {
<&'r str>::from_data(req, data).await.map(Simple)
}
}

View File

@ -26,7 +26,7 @@ struct Simple(String);
impl<'r> FromData<'r> for Simple {
type Error = std::io::Error;
async fn from_data(req: &'r Request<'_>, data: Data) -> data::Outcome<Self, Self::Error> {
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> data::Outcome<'r, Self> {
String::from_data(req, data).await.map(Simple)
}
}
@ -78,7 +78,7 @@ fn post2(
#[allow(dead_code)]
#[post("/<_unused_param>?<_unused_query>", data="<_unused_data>")]
fn test_unused_params(_unused_param: String, _unused_query: String, _unused_data: Data) {
fn test_unused_params(_unused_param: String, _unused_query: String, _unused_data: Data<'_>) {
}
#[test]

View File

@ -53,4 +53,4 @@ error[E0277]: the trait bound `usize: Responder<'_, '_>` is not satisfied
28 | fn foo() -> usize { 0 }
| ^^^^^ the trait `Responder<'_, '_>` is not implemented for `usize`
|
= note: required by `route::handler::<impl Outcome<rocket::Response<'o>, Status, rocket::Data>>::from`
= note: required by `route::handler::<impl Outcome<rocket::Response<'o>, Status, rocket::Data<'o>>>::from`

View File

@ -38,7 +38,7 @@ error[E0277]: the trait bound `Q: FromData<'_>` is not satisfied
|
::: $WORKSPACE/core/lib/src/data/from_data.rs
|
| async fn from_data(req: &'r Request<'_>, data: Data) -> Outcome<Self, Self::Error>;
| async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self>;
| -- required by this bound in `rocket::data::FromData::from_data`
error[E0277]: the trait bound `Q: FromRequest<'_>` is not satisfied

View File

@ -53,4 +53,4 @@ error[E0277]: the trait bound `usize: Responder<'_, '_>` is not satisfied
28 | fn foo() -> usize { 0 }
| ^^^^^ the trait `Responder<'_, '_>` is not implemented for `usize`
|
= note: required by `route::handler::<impl Outcome<rocket::Response<'o>, Status, rocket::Data>>::from`
= note: required by `route::handler::<impl Outcome<rocket::Response<'o>, Status, rocket::Data<'o>>>::from`

View File

@ -38,7 +38,7 @@ error[E0277]: the trait bound `Q: FromData<'_>` is not satisfied
|
::: $WORKSPACE/core/lib/src/data/from_data.rs
|
| async fn from_data(req: &'r Request<'_>, data: Data) -> Outcome<Self, Self::Error>;
| async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self>;
| -- required by this bound in `rocket::data::FromData::from_data`
error[E0277]: the trait bound `Q: FromRequest<'_>` is not satisfied

View File

@ -16,10 +16,10 @@ fn f2() {}
// Check if a data argument is used with a usually non-payload bearing method.
#[get("/", data = "<_foo>")]
fn g0(_foo: rocket::Data) {}
fn g0(_foo: rocket::Data<'_>) {}
#[head("/", data = "<_foo>")]
fn g1(_foo: rocket::Data) {}
fn g1(_foo: rocket::Data<'_>) {}
fn main() {
compile_error!("checking for warnings!")

View File

@ -223,21 +223,21 @@ macro_rules! impl_strict_from_form_field_from_capped {
fn from_value(f: ValueField<'v>) -> Result<'v, Self> {
let capped = <Capped<$T> as FromFormField<'v>>::from_value(f)?;
if capped.is_complete() {
Ok(capped.value)
} else {
Err((None, Some(capped.n.written)))?
if !capped.is_complete() {
Err((None, Some(capped.n.written)))?;
}
Ok(capped.value)
}
async fn from_data(field: DataField<'v, '_>) -> Result<'v, Self> {
let capped = <Capped<$T> as FromFormField<'v>>::from_data(field);
let capped = capped.await?;
if capped.is_complete() {
Ok(capped.value)
} else {
Err((None, Some(capped.n.written)))?
if !capped.is_complete() {
Err((None, Some(capped.n.written)))?;
}
Ok(capped.value)
}
}
};)
@ -251,8 +251,8 @@ macro_rules! impl_strict_from_data_from_capped {
async fn from_data(
r: &'r $crate::Request<'_>,
d: $crate::Data
) -> $crate::data::Outcome<Self, Self::Error> {
d: $crate::Data<'r>
) -> $crate::data::Outcome<'r, Self> {
use $crate::outcome::Outcome::*;
use std::io::{Error, ErrorKind::UnexpectedEof};

View File

@ -15,7 +15,7 @@ pub const PEEK_BYTES: usize = 512;
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// # type DataGuard = rocket::data::Data;
/// # type DataGuard = String;
/// #[post("/submit", data = "<var>")]
/// fn submit(var: DataGuard) { /* ... */ }
/// # fn main() { }
@ -37,15 +37,15 @@ pub const PEEK_BYTES: usize = 512;
/// The `peek` method returns a slice containing at most 512 bytes of buffered
/// body data. This enables partially or fully reading from a `Data` object
/// without consuming the `Data` object.
pub struct Data {
pub struct Data<'r> {
buffer: Vec<u8>,
is_complete: bool,
stream: StreamReader,
stream: StreamReader<'r>,
}
impl Data {
impl<'r> Data<'r> {
/// Create a `Data` from a recognized `stream`.
pub(crate) fn from<S: Into<StreamReader>>(stream: S) -> Data {
pub(crate) fn from<S: Into<StreamReader<'r>>>(stream: S) -> Data<'r> {
// TODO.async: This used to also set the read timeout to 5 seconds.
// Such a short read timeout is likely no longer necessary, but some
// kind of idle timeout should be implemented.
@ -57,7 +57,7 @@ impl Data {
/// This creates a `data` object from a local data source `data`.
#[inline]
pub(crate) fn local(data: Vec<u8>) -> Data {
pub(crate) fn local(data: Vec<u8>) -> Data<'r> {
Data {
buffer: data,
stream: StreamReader::empty(),
@ -78,11 +78,11 @@ impl Data {
/// use rocket::data::{Data, ToByteUnit};
///
/// # const SIZE_LIMIT: u64 = 2 << 20; // 2MiB
/// fn handler(data: Data) {
/// fn handler(data: Data<'_>) {
/// let stream = data.open(2.mebibytes());
/// }
/// ```
pub fn open(self, limit: ByteUnit) -> DataStream {
pub fn open(self, limit: ByteUnit) -> DataStream<'r> {
DataStream::new(self.buffer, self.stream, limit.into())
}
@ -101,7 +101,7 @@ impl Data {
///
/// ```rust
/// use rocket::request::{self, Request, FromRequest};
/// use rocket::data::{self, Data, FromData};
/// use rocket::data::{Data, FromData, Outcome};
/// # struct MyType;
/// # type MyError = String;
///
@ -109,12 +109,9 @@ impl Data {
/// impl<'r> FromData<'r> for MyType {
/// type Error = MyError;
///
/// async fn from_data(
/// req: &'r Request<'_>,
/// mut data: Data
/// ) -> data::Outcome<Self, Self::Error> {
/// async fn from_data(r: &'r Request<'_>, mut data: Data<'r>) -> Outcome<'r, Self> {
/// if data.peek(2).await != b"hi" {
/// return data::Outcome::Forward(data)
/// return Outcome::Forward(data)
/// }
///
/// /* .. */
@ -139,7 +136,7 @@ impl Data {
/// }
/// }
///
/// async fn on_request(&self, req: &mut Request<'_>, data: &mut Data) {
/// async fn on_request(&self, req: &mut Request<'_>, data: &mut Data<'_>) {
/// if data.peek(2).await == b"hi" {
/// /* do something; body data starts with `"hi"` */
/// }
@ -179,7 +176,7 @@ impl Data {
/// ```rust
/// use rocket::data::Data;
///
/// async fn handler(mut data: Data) {
/// async fn handler(mut data: Data<'_>) {
/// if data.peek_complete() {
/// println!("All of the data: {:?}", data.peek(512).await);
/// }

View File

@ -39,14 +39,14 @@ use crate::data::{Capped, N};
///
/// [`DataStream::stream_to(&mut vec)`]: DataStream::stream_to()
/// [`DataStream::stream_to(&mut file)`]: DataStream::stream_to()
pub struct DataStream {
pub(crate) chain: Take<Chain<Cursor<Vec<u8>>, StreamReader>>,
pub struct DataStream<'r> {
pub(crate) chain: Take<Chain<Cursor<Vec<u8>>, StreamReader<'r>>>,
}
/// An adapter: turns a `T: Stream` (in `StreamKind`) into a `tokio::AsyncRead`.
pub struct StreamReader {
pub struct StreamReader<'r> {
state: State,
inner: StreamKind,
inner: StreamKind<'r>,
}
/// The current state of `StreamReader` `AsyncRead` adapter.
@ -57,13 +57,14 @@ enum State {
}
/// The kinds of streams we accept as `Data`.
enum StreamKind {
Body(hyper::Body),
Multipart(multer::Field<'static>)
enum StreamKind<'r> {
Empty,
Body(&'r mut hyper::Body),
Multipart(multer::Field<'r>)
}
impl DataStream {
pub(crate) fn new(buf: Vec<u8>, stream: StreamReader, limit: u64) -> Self {
impl<'r> DataStream<'r> {
pub(crate) fn new(buf: Vec<u8>, stream: StreamReader<'r>, limit: u64) -> Self {
let chain = Chain::new(Cursor::new(buf), stream).take(limit);
Self { chain }
}
@ -71,7 +72,7 @@ impl DataStream {
/// Whether a previous read exhausted the set limit _and then some_.
async fn limit_exceeded(&mut self) -> io::Result<bool> {
#[cold]
async fn _limit_exceeded(stream: &mut DataStream) -> io::Result<bool> {
async fn _limit_exceeded(stream: &mut DataStream<'_>) -> io::Result<bool> {
stream.chain.set_limit(1);
let mut buf = [0u8; 1];
Ok(stream.read(&mut buf).await? != 0)
@ -87,7 +88,7 @@ impl DataStream {
/// ```rust
/// use rocket::data::{Data, ToByteUnit};
///
/// async fn f(data: Data) {
/// async fn f(data: Data<'_>) {
/// let definitely_have_n_bytes = data.open(1.kibibytes()).hint();
/// }
/// ```
@ -111,7 +112,7 @@ impl DataStream {
/// use std::io;
/// use rocket::data::{Data, ToByteUnit};
///
/// async fn data_guard(mut data: Data) -> io::Result<String> {
/// async fn data_guard(mut data: Data<'_>) -> io::Result<String> {
/// // write all of the data to stdout
/// let written = data.open(512.kibibytes())
/// .stream_to(tokio::io::stdout()).await?;
@ -136,7 +137,7 @@ impl DataStream {
/// use std::io;
/// use rocket::data::{Data, ToByteUnit};
///
/// async fn data_guard(mut data: Data) -> io::Result<String> {
/// async fn data_guard(mut data: Data<'_>) -> io::Result<String> {
/// // write all of the data to stdout
/// let written = data.open(512.kibibytes())
/// .stream_precise_to(tokio::io::stdout()).await?;
@ -159,7 +160,7 @@ impl DataStream {
/// use std::io;
/// use rocket::data::{Data, ToByteUnit};
///
/// async fn data_guard(data: Data) -> io::Result<Vec<u8>> {
/// async fn data_guard(data: Data<'_>) -> io::Result<Vec<u8>> {
/// let bytes = data.open(4.kibibytes()).into_bytes().await?;
/// if !bytes.is_complete() {
/// println!("there are bytes remaining in the stream");
@ -182,7 +183,7 @@ impl DataStream {
/// use std::io;
/// use rocket::data::{Data, ToByteUnit};
///
/// async fn data_guard(data: Data) -> io::Result<String> {
/// async fn data_guard(data: Data<'_>) -> io::Result<String> {
/// let string = data.open(10.bytes()).into_string().await?;
/// if !string.is_complete() {
/// println!("there are bytes remaining in the stream");
@ -208,7 +209,7 @@ impl DataStream {
/// use std::io;
/// use rocket::data::{Data, ToByteUnit};
///
/// async fn data_guard(mut data: Data) -> io::Result<String> {
/// async fn data_guard(mut data: Data<'_>) -> io::Result<String> {
/// let file = data.open(1.megabytes()).into_file("/static/file").await?;
/// if !file.is_complete() {
/// println!("there are bytes remaining in the stream");
@ -226,25 +227,25 @@ impl DataStream {
// TODO.async: Consider implementing `AsyncBufRead`.
impl StreamReader {
impl StreamReader<'_> {
pub fn empty() -> Self {
Self { inner: StreamKind::Body(hyper::Body::empty()), state: State::Done }
Self { inner: StreamKind::Empty, state: State::Done }
}
}
impl From<hyper::Body> for StreamReader {
fn from(body: hyper::Body) -> Self {
impl<'r> From<&'r mut hyper::Body> for StreamReader<'r> {
fn from(body: &'r mut hyper::Body) -> Self {
Self { inner: StreamKind::Body(body), state: State::Pending }
}
}
impl From<multer::Field<'static>> for StreamReader {
fn from(field: multer::Field<'static>) -> Self {
impl<'r> From<multer::Field<'r>> for StreamReader<'r> {
fn from(field: multer::Field<'r>) -> Self {
Self { inner: StreamKind::Multipart(field), state: State::Pending }
}
}
impl AsyncRead for DataStream {
impl AsyncRead for DataStream<'_> {
#[inline(always)]
fn poll_read(
mut self: Pin<&mut Self>,
@ -255,7 +256,7 @@ impl AsyncRead for DataStream {
}
}
impl Stream for StreamKind {
impl Stream for StreamKind<'_> {
type Item = io::Result<hyper::Bytes>;
fn poll_next(
@ -267,6 +268,7 @@ impl Stream for StreamKind {
.map_err_ext(|e| io::Error::new(io::ErrorKind::Other, e)),
StreamKind::Multipart(mp) => Pin::new(mp).poll_next(cx)
.map_err_ext(|e| io::Error::new(io::ErrorKind::Other, e)),
StreamKind::Empty => Poll::Ready(None),
}
}
@ -274,11 +276,12 @@ impl Stream for StreamKind {
match self {
StreamKind::Body(body) => body.size_hint(),
StreamKind::Multipart(mp) => mp.size_hint(),
StreamKind::Empty => (0, Some(0)),
}
}
}
impl AsyncRead for StreamReader {
impl AsyncRead for StreamReader<'_> {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,

View File

@ -5,15 +5,16 @@ use crate::outcome::{self, IntoOutcome, try_outcome, Outcome::*};
/// Type alias for the `Outcome` of [`FromData`].
///
/// [`FromData`]: crate::data::FromData
pub type Outcome<S, E> = outcome::Outcome<S, (Status, E), Data>;
/// [`FromData`]: crTte::data::FromData
pub type Outcome<'r, T, E = <T as FromData<'r>>::Error>
= outcome::Outcome<T, (Status, E), Data<'r>>;
impl<S, E> IntoOutcome<S, (Status, E), Data> for Result<S, E> {
impl<'r, S, E> IntoOutcome<S, (Status, E), Data<'r>> for Result<S, E> {
type Failure = Status;
type Forward = Data;
type Forward = Data<'r>;
#[inline]
fn into_outcome(self, status: Status) -> Outcome<S, E> {
fn into_outcome(self, status: Status) -> Outcome<'r, S, E> {
match self {
Ok(val) => Success(val),
Err(err) => Failure((status, err))
@ -21,7 +22,7 @@ impl<S, E> IntoOutcome<S, (Status, E), Data> for Result<S, E> {
}
#[inline]
fn or_forward(self, data: Data) -> Outcome<S, E> {
fn or_forward(self, data: Data<'r>) -> Outcome<'r, S, E> {
match self {
Ok(val) => Success(val),
Err(_) => Forward(data)
@ -41,7 +42,7 @@ impl<S, E> IntoOutcome<S, (Status, E), Data> for Result<S, E> {
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// # type DataGuard = rocket::data::Data;
/// # type DataGuard = String;
/// #[post("/submit", data = "<var>")]
/// fn submit(var: DataGuard) { /* ... */ }
/// ```
@ -66,7 +67,7 @@ impl<S, E> IntoOutcome<S, (Status, E), Data> for Result<S, E> {
/// impl<'r> FromData<'r> for MyType {
/// type Error = MyError;
///
/// async fn from_data(req: &'r Request<'_>, data: Data) -> data::Outcome<Self, MyError> {
/// async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> data::Outcome<'r, Self> {
/// /* .. */
/// # unimplemented!()
/// }
@ -122,7 +123,7 @@ impl<S, E> IntoOutcome<S, (Status, E), Data> for Result<S, E> {
/// impl<'r> FromData<'r> for Person<'r> {
/// type Error = Error;
///
/// async fn from_data(req: &'r Request<'_>, data: Data) -> data::Outcome<Self, Error> {
/// async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> data::Outcome<'r, Self> {
/// use Error::*;
/// use rocket::outcome::Outcome::*;
///
@ -190,7 +191,7 @@ pub trait FromData<'r>: Sized {
/// If validation and parsing succeeds, an outcome of `Success` is returned.
/// If the data is not appropriate given the type of `Self`, `Forward` is
/// returned. If parsing fails, `Failure` is returned.
async fn from_data(req: &'r Request<'_>, data: Data) -> Outcome<Self, Self::Error>;
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self>;
}
use crate::data::Capped;
@ -199,7 +200,7 @@ use crate::data::Capped;
impl<'r> FromData<'r> for Capped<String> {
type Error = std::io::Error;
async fn from_data(req: &'r Request<'_>, data: Data) -> Outcome<Self, Self::Error> {
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
let limit = req.limits().get("string").unwrap_or(Limits::STRING);
data.open(limit).into_string().await.into_outcome(Status::BadRequest)
}
@ -211,7 +212,7 @@ impl_strict_from_data_from_capped!(String);
impl<'r> FromData<'r> for Capped<&'r str> {
type Error = std::io::Error;
async fn from_data(req: &'r Request<'_>, data: Data) -> Outcome<Self, Self::Error> {
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
let capped = try_outcome!(<Capped<String>>::from_data(req, data).await);
let string = capped.map(|s| local_cache!(req, s).as_str());
Success(string)
@ -224,7 +225,7 @@ impl_strict_from_data_from_capped!(&'r str);
impl<'r> FromData<'r> for Capped<&'r RawStr> {
type Error = std::io::Error;
async fn from_data(req: &'r Request<'_>, data: Data) -> Outcome<Self, Self::Error> {
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
let capped = try_outcome!(<Capped<String>>::from_data(req, data).await);
let raw = capped.map(|s| RawStr::new(local_cache!(req, s)));
Success(raw)
@ -237,7 +238,7 @@ impl_strict_from_data_from_capped!(&'r RawStr);
impl<'r> FromData<'r> for Capped<std::borrow::Cow<'_, str>> {
type Error = std::io::Error;
async fn from_data(req: &'r Request<'_>, data: Data) -> Outcome<Self, Self::Error> {
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
let capped = try_outcome!(<Capped<String>>::from_data(req, data).await);
Success(capped.map(|s| s.into()))
}
@ -249,7 +250,7 @@ impl_strict_from_data_from_capped!(std::borrow::Cow<'_, str>);
impl<'r> FromData<'r> for Capped<&'r [u8]> {
type Error = std::io::Error;
async fn from_data(req: &'r Request<'_>, data: Data) -> Outcome<Self, Self::Error> {
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
let capped = try_outcome!(<Capped<Vec<u8>>>::from_data(req, data).await);
let raw = capped.map(|b| local_cache!(req, b).as_slice());
Success(raw)
@ -262,7 +263,7 @@ impl_strict_from_data_from_capped!(&'r [u8]);
impl<'r> FromData<'r> for Capped<Vec<u8>> {
type Error = std::io::Error;
async fn from_data(req: &'r Request<'_>, data: Data) -> Outcome<Self, Self::Error> {
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
let limit = req.limits().get("bytes").unwrap_or(Limits::BYTES);
data.open(limit).into_bytes().await.into_outcome(Status::BadRequest)
}
@ -271,10 +272,10 @@ impl<'r> FromData<'r> for Capped<Vec<u8>> {
impl_strict_from_data_from_capped!(Vec<u8>);
#[crate::async_trait]
impl<'r> FromData<'r> for Data {
impl<'r> FromData<'r> for Data<'r> {
type Error = std::convert::Infallible;
async fn from_data(_: &'r Request<'_>, data: Data) -> Outcome<Self, Self::Error> {
async fn from_data(_: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
Success(data)
}
}
@ -283,10 +284,7 @@ impl<'r> FromData<'r> for Data {
impl<'r, T: FromData<'r> + 'r> FromData<'r> for Result<T, T::Error> {
type Error = std::convert::Infallible;
async fn from_data(
req: &'r Request<'_>,
data: Data
) -> Outcome<Result<T, <T as FromData<'r>>::Error>, Self::Error> {
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
match T::from_data(req, data).await {
Success(v) => Success(Ok(v)),
Failure((_, e)) => Success(Err(e)),
@ -299,7 +297,7 @@ impl<'r, T: FromData<'r> + 'r> FromData<'r> for Result<T, T::Error> {
impl<'r, T: FromData<'r>> FromData<'r> for Option<T> {
type Error = std::convert::Infallible;
async fn from_data(req: &'r Request<'_>, data: Data) -> Outcome<Self, Self::Error> {
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
match T::from_data(req, data).await {
Success(v) => Success(Some(v)),
Failure(..) | Forward(..) => Success(None),

View File

@ -93,7 +93,7 @@ use crate::http::uncased::Uncased;
/// use rocket::data::{Data, Limits, ToByteUnit};
///
/// #[post("/echo", data = "<data>")]
/// async fn echo(data: Data, limits: &Limits) -> io::Result<String> {
/// async fn echo(data: Data<'_>, limits: &Limits) -> io::Result<String> {
/// let limit = limits.get("data").unwrap_or(1.mebibytes());
/// Ok(data.open(limit).into_string().await?.value)
/// }
@ -112,7 +112,7 @@ use crate::http::uncased::Uncased;
/// impl<'r> FromData<'r> for MyType {
/// type Error = MyError;
///
/// async fn from_data(req: &'r Request<'_>, data: Data) -> data::Outcome<Self, MyError> {
/// async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> data::Outcome<'r, Self> {
/// let limit = req.limits().get("my-data-type");
/// /* .. */
/// # unimplemented!()

View File

@ -59,7 +59,7 @@ enum AdHocKind {
Liftoff(Once<dyn for<'a> FnOnce(&'a Rocket<Orbit>) -> BoxFuture<'a, ()> + Send + 'static>),
/// An ad-hoc **request** fairing. Called when a request is received.
Request(Box<dyn for<'a> Fn(&'a mut Request<'_>, &'a Data)
Request(Box<dyn for<'a> Fn(&'a mut Request<'_>, &'a Data<'_>)
-> BoxFuture<'a, ()> + Send + Sync + 'static>),
/// An ad-hoc **response** fairing. Called when a response is ready to be
@ -150,7 +150,7 @@ impl AdHoc {
/// });
/// ```
pub fn on_request<F: Send + Sync + 'static>(name: &'static str, f: F) -> AdHoc
where F: for<'a> Fn(&'a mut Request<'_>, &'a Data) -> BoxFuture<'a, ()>
where F: for<'a> Fn(&'a mut Request<'_>, &'a Data<'_>) -> BoxFuture<'a, ()>
{
AdHoc { name, kind: AdHocKind::Request(Box::new(f)) }
}
@ -247,7 +247,7 @@ impl Fairing for AdHoc {
}
}
async fn on_request(&self, req: &mut Request<'_>, data: &mut Data) {
async fn on_request(&self, req: &mut Request<'_>, data: &mut Data<'_>) {
if let AdHocKind::Request(ref f) = self.kind {
f(req, data).await
}

View File

@ -140,7 +140,7 @@ impl Fairings {
}
#[inline(always)]
pub async fn handle_request(&self, req: &mut Request<'_>, data: &mut Data) {
pub async fn handle_request(&self, req: &mut Request<'_>, data: &mut Data<'_>) {
for fairing in iter!(self.request) {
fairing.on_request(req, data).await
}

View File

@ -237,7 +237,7 @@ pub type Result<T = Rocket<Build>, E = Rocket<Build>> = std::result::Result<T, E
/// # unimplemented!()
/// }
///
/// async fn on_request(&self, req: &mut Request<'_>, data: &mut Data) {
/// async fn on_request(&self, req: &mut Request<'_>, data: &mut Data<'_>) {
/// /* ... */
/// # unimplemented!()
/// }
@ -286,7 +286,7 @@ pub type Result<T = Rocket<Build>, E = Rocket<Build>> = std::result::Result<T, E
/// }
/// }
///
/// async fn on_request(&self, req: &mut Request<'_>, _: &mut Data) {
/// async fn on_request(&self, req: &mut Request<'_>, _: &mut Data<'_>) {
/// if req.method() == Method::Get {
/// self.get.fetch_add(1, Ordering::Relaxed);
/// } else if req.method() == Method::Post {
@ -349,7 +349,7 @@ pub type Result<T = Rocket<Build>, E = Rocket<Build>> = std::result::Result<T, E
/// }
///
/// /// Stores the start time of the request in request-local state.
/// async fn on_request(&self, request: &mut Request<'_>, _: &mut Data) {
/// async fn on_request(&self, request: &mut Request<'_>, _: &mut Data<'_>) {
/// // Store a `TimerStart` instead of directly storing a `SystemTime`
/// // to ensure that this usage doesn't conflict with anything else
/// // that might store a `SystemTime` in request-local cache.
@ -457,7 +457,7 @@ pub trait Fairing: Send + Sync + Any + 'static {
/// ## Default Implementation
///
/// The default implementation of this method does nothing.
async fn on_request(&self, _req: &mut Request<'_>, _data: &mut Data) {}
async fn on_request(&self, _req: &mut Request<'_>, _data: &mut Data<'_>) {}
/// The response callback.
///
@ -490,7 +490,7 @@ impl<T: Fairing> Fairing for std::sync::Arc<T> {
}
#[inline]
async fn on_request(&self, req: &mut Request<'_>, data: &mut Data) {
async fn on_request(&self, req: &mut Request<'_>, data: &mut Data<'_>) {
(self as &T).on_request(req, data).await
}

View File

@ -804,11 +804,19 @@ impl fmt::Display for ErrorKind<'_> {
match self {
ErrorKind::InvalidLength { min, max } => {
match (min, max) {
(None, None) => write!(f, "unexpected or incomplete")?,
(None, Some(k)) => write!(f, "length cannot exceed {}", k)?,
(Some(1), None) => write!(f, "value cannot be empty")?,
(Some(k), None) => write!(f, "length must be at least {}", k)?,
(Some(i), Some(j)) => write!(f, "length must be between {} and {}", i, j)?,
(None, None) => write!(f, "invalid length: incomplete")?,
(None, Some(k)) if *k < 1024 => write!(f, "length cannot exceed {}", k)?,
(None, Some(k)) => write!(f, "size must not exceed {}", ByteUnit::from(*k))?,
(Some(1), None) => write!(f, "cannot be empty")?,
(Some(k), None) if *k < 1024 => write!(f, "expected at least {}", k)?,
(Some(k), None) => write!(f, "size must be at least {}", ByteUnit::from(*k))?,
(Some(i), Some(j)) if *i < 1024 && *j < 1024 => {
write!(f, "length must be between {} and {}", i, j)?;
}
(Some(i), Some(j)) => {
let (i, j) = (ByteUnit::from(*i), ByteUnit::from(*j));
write!(f, "size must be between {} and {}", i, j)?;
}
}
}
ErrorKind::InvalidChoice { choices } => {

View File

@ -33,7 +33,7 @@ pub struct DataField<'r, 'i> {
/// The request in which the form field was submitted.
pub request: &'r Request<'i>,
/// The raw data stream.
pub data: Data,
pub data: Data<'r>,
}
impl<'v> ValueField<'v> {

View File

@ -299,7 +299,7 @@ impl<T> DerefMut for Form<T> {
impl<'r, T: FromForm<'r>> FromData<'r> for Form<T> {
type Error = Errors<'r>;
async fn from_data(req: &'r Request<'_>, data: Data) -> Outcome<Self, Self::Error> {
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
use either::Either;
let mut parser = try_outcome!(Parser::new(req, data).await);

View File

@ -21,7 +21,7 @@ pub struct Buffer {
pub struct MultipartParser<'r, 'i> {
request: &'r Request<'i>,
buffer: &'r Buffer,
source: Multipart<'static>,
source: Multipart<'r>,
done: bool,
}
@ -36,7 +36,10 @@ pub enum Parser<'r, 'i> {
}
impl<'r, 'i> Parser<'r, 'i> {
pub async fn new(req: &'r Request<'i>, data: Data) -> Outcome<Parser<'r, 'i>, Errors<'r>> {
pub async fn new(
req: &'r Request<'i>,
data: Data<'r>
) -> Outcome<'r, Parser<'r, 'i>, Errors<'r>> {
let parser = match req.content_type() {
Some(c) if c.is_form() => Self::from_form(req, data).await,
Some(c) if c.is_form_data() => Self::from_multipart(req, data).await,
@ -49,11 +52,11 @@ impl<'r, 'i> Parser<'r, 'i> {
}
}
async fn from_form(req: &'r Request<'i>, data: Data) -> Result<'r, Parser<'r, 'i>> {
async fn from_form(req: &'r Request<'i>, data: Data<'r>) -> Result<'r, Parser<'r, 'i>> {
let limit = req.limits().get("form").unwrap_or(Limits::FORM);
let string = data.open(limit).into_string().await?;
if !string.is_complete() {
Err((None, Some(limit.as_u64())))?
Err((None, Some(limit.as_u64())))?;
}
Ok(Parser::RawStr(RawStrParser {
@ -62,7 +65,7 @@ impl<'r, 'i> Parser<'r, 'i> {
}))
}
async fn from_multipart(req: &'r Request<'i>, data: Data) -> Result<'r, Parser<'r, 'i>> {
async fn from_multipart(req: &'r Request<'i>, data: Data<'r>) -> Result<'r, Parser<'r, 'i>> {
let boundary = req.content_type()
.ok_or(multer::Error::NoMultipart)?
.param("boundary")

View File

@ -184,7 +184,7 @@ impl Into<Vec<Route>> for FileServer {
#[crate::async_trait]
impl Handler for FileServer {
async fn handle<'r>(&self, req: &'r Request<'_>, data: Data) -> Outcome<'r> {
async fn handle<'r>(&self, req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r> {
use crate::http::uri::fmt::Path;
// Get the segments as a `PathBuf`, allowing dotfiles requested.

View File

@ -3,7 +3,7 @@ use std::path::{PathBuf, Path};
use crate::Request;
use crate::http::{ContentType, Status};
use crate::data::{FromData, Data, Capped, N, Limits};
use crate::data::{self, FromData, Data, Capped, N, Limits};
use crate::form::{FromFormField, ValueField, DataField, error::Errors};
use crate::outcome::IntoOutcome;
use crate::fs::FileName;
@ -441,7 +441,7 @@ impl<'v> TempFile<'v> {
async fn from<'a>(
req: &Request<'_>,
data: Data,
data: Data<'_>,
file_name: Option<&'a FileName>,
content_type: Option<ContentType>,
) -> io::Result<Capped<TempFile<'a>>> {
@ -489,10 +489,7 @@ impl<'v> FromFormField<'v> for Capped<TempFile<'v>> {
impl<'r> FromData<'r> for Capped<TempFile<'_>> {
type Error = io::Error;
async fn from_data(
req: &'r crate::Request<'_>,
data: crate::Data
) -> crate::data::Outcome<Self, Self::Error> {
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> data::Outcome<'r, Self> {
use yansi::Paint;
let has_form = |ty: &ContentType| ty.is_form_data() || ty.is_form();

View File

@ -26,7 +26,7 @@
//!
//! ```rust
//! # use rocket::post;
//! # type S = rocket::data::Data;
//! # type S = String;
//! #[post("/", data = "<my_val>")]
//! fn hello(my_val: S) { /* ... */ }
//! ```
@ -49,7 +49,7 @@
//!
//! ```rust
//! # use rocket::post;
//! # type S = rocket::data::Data;
//! # type S = Option<String>;
//! # type E = std::convert::Infallible;
//! #[post("/", data = "<my_val>")]
//! fn hello(my_val: Result<S, E>) { /* ... */ }
@ -73,7 +73,7 @@
//!
//! ```rust
//! # use rocket::post;
//! # type S = rocket::data::Data;
//! # type S = String;
//! #[post("/", data = "<my_val>")]
//! fn hello(my_val: S) { /* ... */ }
//! ```

View File

@ -290,7 +290,7 @@ impl Rocket<Build> {
/// use rocket::{Request, Route, Data, route};
/// use rocket::http::Method;
///
/// fn hi<'r>(req: &'r Request, _: Data) -> route::BoxFuture<'r> {
/// fn hi<'r>(req: &'r Request, _: Data<'r>) -> route::BoxFuture<'r> {
/// route::Outcome::from(req, "Hello!").pin()
/// }
///

View File

@ -4,7 +4,7 @@ use crate::http::Status;
/// Type alias for the return type of a [`Route`](crate::Route)'s
/// [`Handler::handle()`].
pub type Outcome<'r> = crate::outcome::Outcome<Response<'r>, Status, Data>;
pub type Outcome<'r> = crate::outcome::Outcome<Response<'r>, Status, Data<'r>>;
/// Type alias for the return type of a _raw_ [`Route`](crate::Route)'s
/// [`Handler`].
@ -53,7 +53,7 @@ pub type BoxFuture<'r, T = Outcome<'r>> = futures::future::BoxFuture<'r, T>;
///
/// #[rocket::async_trait]
/// impl Handler for CustomHandler {
/// async fn handle<'r>(&self, req: &'r Request<'_>, data: Data) -> Outcome<'r> {
/// async fn handle<'r>(&self, req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r> {
/// match self.0 {
/// Kind::Simple => Outcome::from(req, "simple"),
/// Kind::Intermediate => Outcome::from(req, "intermediate"),
@ -145,18 +145,18 @@ pub trait Handler: Cloneable + Send + Sync + 'static {
/// generate a response. Otherwise, if the return value is `Forward(Data)`,
/// the next matching route is attempted. If there are no other matching
/// routes, the `404` error catcher is invoked.
async fn handle<'r>(&self, request: &'r Request<'_>, data: Data) -> Outcome<'r>;
async fn handle<'r>(&self, request: &'r Request<'_>, data: Data<'r>) -> Outcome<'r>;
}
// We write this manually to avoid double-boxing.
impl<F: Clone + Sync + Send + 'static> Handler for F
where for<'x> F: Fn(&'x Request<'_>, Data) -> BoxFuture<'x>,
where for<'x> F: Fn(&'x Request<'_>, Data<'x>) -> BoxFuture<'x>,
{
#[inline(always)]
fn handle<'r, 'life0, 'life1, 'async_trait>(
&'life0 self,
req: &'r Request<'life1>,
data: Data,
data: Data<'r>,
) -> BoxFuture<'r>
where 'r: 'async_trait,
'life0: 'async_trait,
@ -167,6 +167,7 @@ impl<F: Clone + Sync + Send + 'static> Handler for F
}
}
// FIXME!
impl<'r, 'o: 'r> Outcome<'o> {
/// Return the `Outcome` of response to `req` from `responder`.
///
@ -179,12 +180,12 @@ impl<'r, 'o: 'r> Outcome<'o> {
/// ```rust
/// use rocket::{Request, Data, route};
///
/// fn str_responder<'r>(req: &'r Request, _: Data) -> route::Outcome<'r> {
/// fn str_responder<'r>(req: &'r Request, _: Data<'r>) -> route::Outcome<'r> {
/// route::Outcome::from(req, "Hello, world!")
/// }
/// ```
#[inline]
pub fn from<R: Responder<'r, 'o>>(req: &'r Request<'_>, responder: R) -> Outcome<'o> {
pub fn from<R: Responder<'r, 'o>>(req: &'r Request<'_>, responder: R) -> Outcome<'r> {
match responder.respond_to(req) {
Ok(response) => Outcome::Success(response),
Err(status) => Outcome::Failure(status)
@ -202,12 +203,12 @@ impl<'r, 'o: 'r> Outcome<'o> {
/// ```rust
/// use rocket::{Request, Data, route};
///
/// fn str_responder<'r>(req: &'r Request, _: Data) -> route::Outcome<'r> {
/// fn str_responder<'r>(req: &'r Request, _: Data<'r>) -> route::Outcome<'r> {
/// route::Outcome::from(req, "Hello, world!")
/// }
/// ```
#[inline]
pub fn try_from<R, E>(req: &'r Request<'_>, result: Result<R, E>) -> Outcome<'o>
pub fn try_from<R, E>(req: &'r Request<'_>, result: Result<R, E>) -> Outcome<'r>
where R: Responder<'r, 'o>, E: std::fmt::Debug
{
let responder = result.map_err(crate::response::Debug);
@ -228,12 +229,12 @@ impl<'r, 'o: 'r> Outcome<'o> {
/// ```rust
/// use rocket::{Request, Data, route};
///
/// fn str_responder<'r>(req: &'r Request, data: Data) -> route::Outcome<'r> {
/// fn str_responder<'r>(req: &'r Request, data: Data<'r>) -> route::Outcome<'r> {
/// route::Outcome::from_or_forward(req, data, "Hello, world!")
/// }
/// ```
#[inline]
pub fn from_or_forward<R>(req: &'r Request<'_>, data: Data, responder: R) -> Outcome<'o>
pub fn from_or_forward<R>(req: &'r Request<'_>, data: Data<'r>, responder: R) -> Outcome<'r>
where R: Responder<'r, 'o>
{
match responder.respond_to(req) {
@ -253,12 +254,12 @@ impl<'r, 'o: 'r> Outcome<'o> {
/// use rocket::{Request, Data, route};
/// use rocket::http::Status;
///
/// fn bad_req_route<'r>(_: &'r Request, _: Data) -> route::Outcome<'r> {
/// fn bad_req_route<'r>(_: &'r Request, _: Data<'r>) -> route::Outcome<'r> {
/// route::Outcome::failure(Status::BadRequest)
/// }
/// ```
#[inline(always)]
pub fn failure(code: Status) -> Outcome<'static> {
pub fn failure(code: Status) -> Outcome<'r> {
Outcome::Failure(code)
}
@ -272,19 +273,19 @@ impl<'r, 'o: 'r> Outcome<'o> {
/// ```rust
/// use rocket::{Request, Data, route};
///
/// fn always_forward<'r>(_: &'r Request, data: Data) -> route::Outcome<'r> {
/// fn always_forward<'r>(_: &'r Request, data: Data<'r>) -> route::Outcome<'r> {
/// route::Outcome::forward(data)
/// }
/// ```
#[inline(always)]
pub fn forward(data: Data) -> Outcome<'static> {
pub fn forward(data: Data<'r>) -> Outcome<'r> {
Outcome::Forward(data)
}
}
// INTERNAL: A handler to use when one is needed temporarily.
#[doc(hidden)]
pub fn dummy_handler<'r>(r: &'r Request<'_>, _: Data) -> BoxFuture<'r> {
pub fn dummy_handler<'r>(r: &'r Request<'_>, _: Data<'r>) -> BoxFuture<'r> {
Outcome::from(r, ()).pin()
}

View File

@ -339,7 +339,7 @@ pub struct StaticInfo {
/// The route's format, if any.
pub format: Option<MediaType>,
/// The route's handler, i.e, the annotated function.
pub handler: for<'r> fn(&'r crate::Request<'_>, crate::Data) -> BoxFuture<'r>,
pub handler: for<'r> fn(&'r crate::Request<'_>, crate::Data<'r>) -> BoxFuture<'r>,
/// The route's rank, if any.
pub rank: Option<isize>,
/// Route-derived sentinels, if any.

View File

@ -158,7 +158,7 @@ impl<'r, T: Deserialize<'r>> Json<T> {
serde_json::from_str(s).map(Json).map_err(|e| Error::Parse(s, e))
}
async fn from_data(req: &'r Request<'_>, data: Data) -> Result<Self, Error<'r>> {
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Result<Self, Error<'r>> {
let limit = req.limits().get("json").unwrap_or(Limits::JSON);
let string = match data.open(limit).into_string().await {
Ok(s) if s.is_complete() => s.into_inner(),
@ -177,7 +177,7 @@ impl<'r, T: Deserialize<'r>> Json<T> {
impl<'r, T: Deserialize<'r>> FromData<'r> for Json<T> {
type Error = Error<'r>;
async fn from_data(req: &'r Request<'_>, data: Data) -> Outcome<Self, Self::Error> {
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
match Self::from_data(req, data).await {
Ok(value) => Outcome::Success(value),
Err(Error::Io(e)) if e.kind() == io::ErrorKind::UnexpectedEof => {

View File

@ -146,7 +146,7 @@ impl<'r, T: Deserialize<'r>> MsgPack<T> {
rmp_serde::from_slice(buf).map(MsgPack)
}
async fn from_data(req: &'r Request<'_>, data: Data) -> Result<Self, Error> {
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Result<Self, Error> {
let limit = req.limits().get("msgpack").unwrap_or(Limits::MESSAGE_PACK);
let bytes = match data.open(limit).into_bytes().await {
Ok(buf) if buf.is_complete() => buf.into_inner(),
@ -165,7 +165,7 @@ impl<'r, T: Deserialize<'r>> MsgPack<T> {
impl<'r, T: Deserialize<'r>> FromData<'r> for MsgPack<T> {
type Error = Error;
async fn from_data(req: &'r Request<'_>, data: Data) -> Outcome<Self, Self::Error> {
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
match Self::from_data(req, data).await {
Ok(value) => Outcome::Success(value),
Err(Error::InvalidDataRead(e)) if e.kind() == io::ErrorKind::UnexpectedEof => {

View File

@ -73,7 +73,7 @@ async fn hyper_service_fn(
tokio::spawn(async move {
// Convert a Hyper request into a Rocket request.
let (h_parts, h_body) = hyp_req.into_parts();
let (h_parts, mut h_body) = hyp_req.into_parts();
let mut req = match Request::from_hyp(&rocket, &h_parts, addr) {
Ok(req) => req,
Err(e) => {
@ -89,7 +89,7 @@ async fn hyper_service_fn(
};
// Retrieve the data from the hyper body.
let mut data = Data::from(h_body);
let mut data = Data::from(&mut h_body);
// Dispatch the request to get a response, then write that response out.
let token = rocket.preprocess_request(&mut req, &mut data).await;
@ -168,7 +168,7 @@ impl Rocket<Orbit> {
pub(crate) async fn preprocess_request(
&self,
req: &mut Request<'_>,
data: &mut Data
data: &mut Data<'_>
) -> RequestToken {
// Check if this is a form and if the form contains the special _method
// field which we use to reinterpret the request's method.
@ -198,7 +198,7 @@ impl Rocket<Orbit> {
&'s self,
_token: RequestToken,
request: &'r Request<'s>,
data: Data
data: Data<'r>
) -> Response<'r> {
info!("{}:", request);
@ -228,7 +228,7 @@ impl Rocket<Orbit> {
async fn route_and_process<'s, 'r: 's>(
&'s self,
request: &'r Request<'s>,
data: Data
data: Data<'r>
) -> Response<'r> {
let mut response = match self.route(request, data).await {
Outcome::Success(response) => response,
@ -266,7 +266,7 @@ impl Rocket<Orbit> {
async fn route<'s, 'r: 's>(
&'s self,
request: &'r Request<'s>,
mut data: Data,
mut data: Data<'r>,
) -> route::Outcome<'r> {
// Go through the list of matching routes until we fail or succeed.
for route in self.router.route(request) {

View File

@ -21,7 +21,7 @@ use rocket::data::{self, FromData};
impl<'r> FromData<'r> for HasContentType {
type Error = ();
async fn from_data(req: &'r Request<'_>, data: Data) -> data::Outcome<Self, ()> {
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> data::Outcome<'r, Self> {
req.content_type().map(|_| HasContentType).or_forward(data)
}
}

View File

@ -20,7 +20,7 @@ fn ise() -> &'static str {
"Hey, sorry! :("
}
fn pre_future_route<'r>(_: &'r Request<'_>, _: Data) -> route::BoxFuture<'r> {
fn pre_future_route<'r>(_: &'r Request<'_>, _: Data<'r>) -> route::BoxFuture<'r> {
panic!("hey now...");
}

View File

@ -2,10 +2,10 @@ use rocket::{Rocket, Build};
use rocket::{fairing::AdHoc, http::ContentType, local::blocking::Client};
#[rocket::post("/", data = "<_data>", format = "json")]
fn index(_data: rocket::Data) -> &'static str { "json" }
fn index(_data: rocket::Data<'_>) -> &'static str { "json" }
#[rocket::post("/", data = "<_data>", rank = 2)]
fn other_index(_data: rocket::Data) -> &'static str { "other" }
fn other_index(_data: rocket::Data<'_>) -> &'static str { "other" }
fn rocket() -> Rocket<Build> {
rocket::build()

View File

@ -38,7 +38,7 @@ impl Fairing for Counter {
Ok(rocket.manage(self.clone()).mount("/", routes![counts]))
}
async fn on_request(&self, request: &mut Request<'_>, _: &mut Data) {
async fn on_request(&self, request: &mut Request<'_>, _: &mut Data<'_>) {
if request.method() == Method::Get {
self.get.fetch_add(1, Ordering::Relaxed);
} else if request.method() == Method::Post {

View File

@ -10,15 +10,15 @@ use rocket::response::{Responder, status::Custom};
use rocket::outcome::{try_outcome, IntoOutcome};
use rocket::tokio::fs::File;
fn forward<'r>(_req: &'r Request, data: Data) -> route::BoxFuture<'r> {
fn forward<'r>(_req: &'r Request, data: Data<'r>) -> route::BoxFuture<'r> {
Box::pin(async move { route::Outcome::forward(data) })
}
fn hi<'r>(req: &'r Request, _: Data) -> route::BoxFuture<'r> {
fn hi<'r>(req: &'r Request, _: Data<'r>) -> route::BoxFuture<'r> {
route::Outcome::from(req, "Hello!").pin()
}
fn name<'a>(req: &'a Request, _: Data) -> route::BoxFuture<'a> {
fn name<'a>(req: &'a Request, _: Data<'r>) -> route::BoxFuture<'a> {
let param = req.param::<&'a str>(0)
.and_then(|res| res.ok())
.unwrap_or("unnamed".into());
@ -26,7 +26,7 @@ fn name<'a>(req: &'a Request, _: Data) -> route::BoxFuture<'a> {
route::Outcome::from(req, param).pin()
}
fn echo_url<'r>(req: &'r Request, _: Data) -> route::BoxFuture<'r> {
fn echo_url<'r>(req: &'r Request, _: Data<'r>) -> route::BoxFuture<'r> {
let param_outcome = req.param::<&str>(1)
.and_then(|res| res.ok())
.into_outcome(Status::BadRequest);
@ -36,7 +36,7 @@ fn echo_url<'r>(req: &'r Request, _: Data) -> route::BoxFuture<'r> {
})
}
fn upload<'r>(req: &'r Request, data: Data) -> route::BoxFuture<'r> {
fn upload<'r>(req: &'r Request, data: Data<'r>) -> route::BoxFuture<'r> {
Box::pin(async move {
if !req.content_type().map_or(false, |ct| ct.is_plain()) {
println!(" => Content-Type of upload must be text/plain. Ignoring.");
@ -58,7 +58,7 @@ fn upload<'r>(req: &'r Request, data: Data) -> route::BoxFuture<'r> {
})
}
fn get_upload<'r>(req: &'r Request, _: Data) -> route::BoxFuture<'r> {
fn get_upload<'r>(req: &'r Request, _: Data<'r>) -> route::BoxFuture<'r> {
route::Outcome::from(req, std::fs::File::open(env::temp_dir().join("upload.txt")).ok()).pin()
}
@ -80,7 +80,7 @@ impl CustomHandler {
#[rocket::async_trait]
impl route::Handler for CustomHandler {
async fn handle<'r>(&self, req: &'r Request<'_>, data: Data) -> route::Outcome<'r> {
async fn handle<'r>(&self, req: &'r Request<'_>, data: Data<'r>) -> route::Outcome<'r> {
let self_data = self.data;
let id = req.param::<&str>(0)
.and_then(|res| res.ok())

View File

@ -17,7 +17,7 @@ const HOST: Absolute<'static> = uri!("http://localhost:8000");
const ID_LENGTH: usize = 3;
#[post("/", data = "<paste>")]
async fn upload(paste: Data) -> io::Result<String> {
async fn upload(paste: Data<'_>) -> io::Result<String> {
let id = PasteId::new(ID_LENGTH);
paste.open(128.kibibytes()).into_file(id.file_path()).await?;
Ok(uri!(HOST, retrieve(id)).to_string())

View File

@ -224,7 +224,7 @@ use rocket::Data;
use rocket::response::Debug;
#[post("/", data = "<paste>")]
fn upload(paste: Data) -> std::io::Result<String> {
fn upload(paste: Data<'_>) -> std::io::Result<String> {
# unimplemented!()
/* .. */
}
@ -255,7 +255,7 @@ use rocket::response::Debug;
use rocket::data::{Data, ToByteUnit};
#[post("/", data = "<paste>")]
async fn upload(paste: Data) -> Result<String, Debug<std::io::Error>> {
async fn upload(paste: Data<'_>) -> Result<String, Debug<std::io::Error>> {
let id = PasteId::new(3);
let filename = format!("upload/{id}", id = id);
let url = format!("{host}/{id}\n", host = "http://localhost:8000", id = id);

View File

@ -598,7 +598,7 @@ As an example, consider the following route:
# #[macro_use] extern crate rocket;
# fn main() {}
# type User = rocket::data::Data;
# type User = String;
#[post("/user", format = "application/json", data = "<user>")]
fn new_user(user: User) { /* ... */ }
@ -647,7 +647,7 @@ trait. It looks like this, where `T` is assumed to implement `FromData`:
```rust
# #[macro_use] extern crate rocket;
# type T = rocket::data::Data;
# type T = String;
#[post("/", data = "<input>")]
fn new(input: T) { /* .. */ }
@ -715,7 +715,7 @@ use rocket::tokio;
use rocket::data::{Data, ToByteUnit};
#[post("/debug", data = "<data>")]
async fn debug(data: Data) -> std::io::Result<()> {
async fn debug(data: Data<'_>) -> std::io::Result<()> {
// Stream at most 512KiB all of the body data to stdout.
data.open(512.kibibytes())
.stream_to(tokio::io::stdout())

View File

@ -171,7 +171,7 @@ impl Fairing for Counter {
}
// Increment the counter for `GET` and `POST` requests.
async fn on_request(&self, request: &mut Request<'_>, _: &mut Data) {
async fn on_request(&self, request: &mut Request<'_>, _: &mut Data<'_>) {
match request.method() {
Method::Get => self.get.fetch_add(1, Ordering::Relaxed),
Method::Post => self.post.fetch_add(1, Ordering::Relaxed),