mirror of https://github.com/rwf2/Rocket.git
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:
parent
7595450adc
commit
4c6562cd29
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)*
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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!")
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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);
|
||||
/// }
|
||||
|
|
|
@ -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<'_>,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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!()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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 } => {
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) { /* ... */ }
|
||||
//! ```
|
||||
|
|
|
@ -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()
|
||||
/// }
|
||||
///
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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...");
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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),
|
||||
|
|
Loading…
Reference in New Issue