Use read_to_string (from futures-preview 0.3.0-alpha.18) to more closely match the pre-async code.

This commit is contained in:
Jeb Rosen 2019-08-12 18:38:25 -07:00 committed by Sergio Benitez
parent 0e6841da66
commit aee7f35095
5 changed files with 76 additions and 70 deletions

View File

@ -42,7 +42,7 @@ memcache_pool = ["databases", "memcache", "r2d2-memcache"]
[dependencies] [dependencies]
# Global dependencies. # Global dependencies.
futures-preview = { version = "0.3.0-alpha.17" } futures-preview = { version = "0.3.0-alpha.18" }
rocket_contrib_codegen = { version = "0.5.0-dev", path = "../codegen", optional = true } rocket_contrib_codegen = { version = "0.5.0-dev", path = "../codegen", optional = true }
rocket = { version = "0.5.0-dev", path = "../../core/lib/", default-features = false } rocket = { version = "0.5.0-dev", path = "../../core/lib/", default-features = false }
log = "0.4" log = "0.4"

View File

@ -139,15 +139,10 @@ impl<'a, T: Deserialize<'a>> FromData<'a> for Json<T> {
fn transform(r: &Request<'_>, d: Data) -> TransformFuture<'a, Self::Owned, Self::Error> { fn transform(r: &Request<'_>, d: Data) -> TransformFuture<'a, Self::Owned, Self::Error> {
let size_limit = r.limits().get("json").unwrap_or(LIMIT); let size_limit = r.limits().get("json").unwrap_or(LIMIT);
Box::pin(async move { Box::pin(async move {
let mut v = Vec::with_capacity(512); let mut s = String::with_capacity(512);
let mut reader = d.open().take(size_limit); let mut reader = d.open().take(size_limit);
match reader.read_to_end(&mut v).await { match reader.read_to_string(&mut s).await {
Ok(_) => { Ok(_) => Borrowed(Success(s)),
match String::from_utf8(v) {
Ok(s) => Borrowed(Success(s)),
Err(e) => Borrowed(Failure((Status::BadRequest, JsonError::Io(std::io::Error::new(std::io::ErrorKind::Other, e))))),
}
},
Err(e) => Borrowed(Failure((Status::BadRequest, JsonError::Io(e)))) Err(e) => Borrowed(Failure((Status::BadRequest, JsonError::Io(e))))
} }
}) })

View File

@ -26,7 +26,7 @@ private-cookies = ["rocket_http/private-cookies"]
[dependencies] [dependencies]
rocket_codegen = { version = "0.5.0-dev", path = "../codegen" } rocket_codegen = { version = "0.5.0-dev", path = "../codegen" }
rocket_http = { version = "0.5.0-dev", path = "../http" } rocket_http = { version = "0.5.0-dev", path = "../http" }
futures-preview = { version = "0.3.0-alpha.14", features = ["compat", "io-compat"] } futures-preview = { version = "0.3.0-alpha.18", features = ["compat", "io-compat"] }
tokio = "0.1.16" tokio = "0.1.16"
yansi = "0.5" yansi = "0.5"
log = { version = "0.4", features = ["std"] } log = { version = "0.4", features = ["std"] }

View File

@ -142,7 +142,7 @@ pub type FromDataFuture<'a, T, E> = Pin<Box<dyn Future<Output = Outcome<T, E>> +
/// if the guard returns successfully. /// if the guard returns successfully.
/// ///
/// ```rust /// ```rust
/// # #![feature(proc_macro_hygiene)] /// # #![feature(proc_macro_hygiene, async_await)]
/// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket;
/// # type DataGuard = rocket::data::Data; /// # type DataGuard = rocket::data::Data;
/// #[post("/submit", data = "<var>")] /// #[post("/submit", data = "<var>")]
@ -188,16 +188,20 @@ pub type FromDataFuture<'a, T, E> = Pin<Box<dyn Future<Output = Outcome<T, E>> +
/// `String` (an `&str`). /// `String` (an `&str`).
/// ///
/// ```rust /// ```rust
/// # #![feature(proc_macro_hygiene)] /// # #![feature(proc_macro_hygiene, async_await)]
/// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket;
/// # #[derive(Debug)] /// # #[derive(Debug)]
/// # struct Name<'a> { first: &'a str, last: &'a str, } /// # struct Name<'a> { first: &'a str, last: &'a str, }
/// use std::io::{self, Read}; /// use std::io::{self, Read};
/// ///
/// use futures::io::AsyncReadExt;
///
/// use rocket::{Request, Data, Outcome::*}; /// use rocket::{Request, Data, Outcome::*};
/// use rocket::data::{FromData, Outcome, Transform, Transformed}; /// use rocket::data::{FromData, Outcome, Transform, Transformed, TransformFuture, FromDataFuture};
/// use rocket::http::Status; /// use rocket::http::Status;
/// ///
/// use rocket::AsyncReadExt as _;
///
/// const NAME_LIMIT: u64 = 256; /// const NAME_LIMIT: u64 = 256;
/// ///
/// enum NameError { /// enum NameError {
@ -210,19 +214,22 @@ pub type FromDataFuture<'a, T, E> = Pin<Box<dyn Future<Output = Outcome<T, E>> +
/// type Owned = String; /// type Owned = String;
/// type Borrowed = str; /// type Borrowed = str;
/// ///
/// fn transform(_: &Request, data: Data) -> Transform<Outcome<Self::Owned, Self::Error>> { /// fn transform(_: &Request, data: Data) -> TransformFuture<'a, Self::Owned, Self::Error> {
/// Box::pin(async move {
/// let mut stream = data.open().take(NAME_LIMIT); /// let mut stream = data.open().take(NAME_LIMIT);
/// let mut string = String::with_capacity((NAME_LIMIT / 2) as usize); /// let mut string = String::with_capacity((NAME_LIMIT / 2) as usize);
/// let outcome = match stream.read_to_string(&mut string) { /// let outcome = match stream.read_to_string(&mut string).await {
/// Ok(_) => Success(string), /// Ok(_) => Success(string),
/// Err(e) => Failure((Status::InternalServerError, NameError::Io(e))) /// Err(e) => Failure((Status::InternalServerError, NameError::Io(e)))
/// }; /// };
/// ///
/// // Returning `Borrowed` here means we get `Borrowed` in `from_data`. /// // Returning `Borrowed` here means we get `Borrowed` in `from_data`.
/// Transform::Borrowed(outcome) /// Transform::Borrowed(outcome)
/// })
/// } /// }
/// ///
/// fn from_data(_: &Request, outcome: Transformed<'a, Self>) -> Outcome<Self, Self::Error> { /// fn from_data(_: &Request, outcome: Transformed<'a, Self>) -> FromDataFuture<'a, Self, Self::Error> {
/// Box::pin(async move {
/// // Retrieve a borrow to the now transformed `String` (an &str). This /// // Retrieve a borrow to the now transformed `String` (an &str). This
/// // is only correct because we know we _always_ return a `Borrowed` from /// // is only correct because we know we _always_ return a `Borrowed` from
/// // `transform` above. /// // `transform` above.
@ -236,6 +243,7 @@ pub type FromDataFuture<'a, T, E> = Pin<Box<dyn Future<Output = Outcome<T, E>> +
/// ///
/// // Return successfully. /// // Return successfully.
/// Success(Name { first: splits[0], last: splits[1] }) /// Success(Name { first: splits[0], last: splits[1] })
/// })
/// } /// }
/// } /// }
/// # #[post("/person", data = "<person>")] /// # #[post("/person", data = "<person>")]
@ -435,7 +443,7 @@ impl<'a> FromData<'a> for Data {
/// that you can retrieve it directly from a client's request body: /// that you can retrieve it directly from a client's request body:
/// ///
/// ```rust /// ```rust
/// # #![feature(proc_macro_hygiene)] /// # #![feature(proc_macro_hygiene, async_await)]
/// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket;
/// # type Person = rocket::data::Data; /// # type Person = rocket::data::Data;
/// #[post("/person", data = "<person>")] /// #[post("/person", data = "<person>")]
@ -447,7 +455,7 @@ impl<'a> FromData<'a> for Data {
/// A `FromDataSimple` implementation allowing this looks like: /// A `FromDataSimple` implementation allowing this looks like:
/// ///
/// ```rust /// ```rust
/// # #![feature(proc_macro_hygiene)] /// # #![feature(proc_macro_hygiene, async_await)]
/// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket;
/// # /// #
/// # #[derive(Debug)] /// # #[derive(Debug)]
@ -455,26 +463,32 @@ impl<'a> FromData<'a> for Data {
/// # /// #
/// use std::io::Read; /// use std::io::Read;
/// ///
/// use futures::io::AsyncReadExt;
///
/// use rocket::{Request, Data, Outcome, Outcome::*}; /// use rocket::{Request, Data, Outcome, Outcome::*};
/// use rocket::data::{self, FromDataSimple}; /// use rocket::data::{self, FromDataSimple, FromDataFuture};
/// use rocket::http::{Status, ContentType}; /// use rocket::http::{Status, ContentType};
/// ///
/// use rocket::AsyncReadExt as _;
///
/// // Always use a limit to prevent DoS attacks. /// // Always use a limit to prevent DoS attacks.
/// const LIMIT: u64 = 256; /// const LIMIT: u64 = 256;
/// ///
/// impl FromDataSimple for Person { /// impl FromDataSimple for Person {
/// type Error = String; /// type Error = String;
/// ///
/// fn from_data(req: &Request, data: Data) -> data::Outcome<Self, String> { /// fn from_data(req: &Request, data: Data) -> FromDataFuture<'static, Self, String> {
/// // Ensure the content type is correct before opening the data. /// // Ensure the content type is correct before opening the data.
/// let person_ct = ContentType::new("application", "x-person"); /// let person_ct = ContentType::new("application", "x-person");
/// if req.content_type() != Some(&person_ct) { /// if req.content_type() != Some(&person_ct) {
/// return Outcome::Forward(data); /// return Box::pin(async move { Outcome::Forward(data) });
/// } /// }
/// ///
/// Box::pin(async move {
/// // Read the data into a String. /// // Read the data into a String.
/// let mut string = String::new(); /// let mut string = String::new();
/// if let Err(e) = data.open().take(LIMIT).read_to_string(&mut string) { /// let mut reader = data.open().take(LIMIT);
/// if let Err(e) = reader.read_to_string(&mut string).await {
/// return Failure((Status::InternalServerError, format!("{:?}", e))); /// return Failure((Status::InternalServerError, format!("{:?}", e)));
/// } /// }
/// ///
@ -492,6 +506,7 @@ impl<'a> FromData<'a> for Data {
/// ///
/// // Return successfully. /// // Return successfully.
/// Success(Person { name, age }) /// Success(Person { name, age })
/// })
/// } /// }
/// } /// }
/// # #[post("/person", data = "<person>")] /// # #[post("/person", data = "<person>")]
@ -579,14 +594,11 @@ impl FromDataSimple for String {
#[inline(always)] #[inline(always)]
fn from_data(_: &Request<'_>, data: Data) -> FromDataFuture<'static, Self, Self::Error> { fn from_data(_: &Request<'_>, data: Data) -> FromDataFuture<'static, Self, Self::Error> {
Box::pin(async { Box::pin(async {
let mut stream = data.open(); let mut string = String::new();
let mut buf = Vec::new(); let mut reader = data.open();
if let Err(e) = stream.read_to_end(&mut buf).await { match reader.read_to_string(&mut string).await {
return Failure((Status::BadRequest, e)); Ok(_) => Success(string),
} Err(e) => Failure((Status::BadRequest, e)),
match String::from_utf8(buf) {
Ok(s) => Success(s),
Err(e) => Failure((Status::BadRequest, std::io::Error::new(std::io::ErrorKind::Other, e))),
} }
}) })
} }

View File

@ -196,6 +196,8 @@ impl<'f, T: FromForm<'f> + Send + 'f> FromData<'f> for Form<T> {
request: &Request<'_>, request: &Request<'_>,
data: Data data: Data
) -> TransformFuture<'f, Self::Owned, Self::Error> { ) -> TransformFuture<'f, Self::Owned, Self::Error> {
use std::cmp::min;
if !request.content_type().map_or(false, |ct| ct.is_form()) { if !request.content_type().map_or(false, |ct| ct.is_form()) {
warn_!("Form data does not have form content type."); warn_!("Form data does not have form content type.");
return Box::pin(futures::future::ready(Transform::Borrowed(Forward(data)))); return Box::pin(futures::future::ready(Transform::Borrowed(Forward(data))));
@ -204,15 +206,12 @@ impl<'f, T: FromForm<'f> + Send + 'f> FromData<'f> for Form<T> {
let limit = request.limits().forms; let limit = request.limits().forms;
let mut stream = data.open().take(limit); let mut stream = data.open().take(limit);
Box::pin(async move { Box::pin(async move {
let mut buf = Vec::new(); let mut form_string = String::with_capacity(min(4096, limit) as usize);
if let Err(e) = stream.read_to_end(&mut buf).await { if let Err(e) = stream.read_to_string(&mut form_string).await {
return Transform::Borrowed(Failure((Status::InternalServerError, FormDataError::Io(e)))); return Transform::Borrowed(Failure((Status::InternalServerError, FormDataError::Io(e))));
} }
Transform::Borrowed(match String::from_utf8(buf) { Transform::Borrowed(Success(form_string))
Ok(s) => Success(s),
Err(e) => Failure((Status::BadRequest, FormDataError::Io(std::io::Error::new(std::io::ErrorKind::Other, e)))),
})
}) })
} }