mirror of https://github.com/rwf2/Rocket.git
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:
parent
0e6841da66
commit
aee7f35095
|
@ -42,7 +42,7 @@ memcache_pool = ["databases", "memcache", "r2d2-memcache"]
|
|||
|
||||
[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 = { version = "0.5.0-dev", path = "../../core/lib/", default-features = false }
|
||||
log = "0.4"
|
||||
|
|
|
@ -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> {
|
||||
let size_limit = r.limits().get("json").unwrap_or(LIMIT);
|
||||
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);
|
||||
match reader.read_to_end(&mut v).await {
|
||||
Ok(_) => {
|
||||
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))))),
|
||||
}
|
||||
},
|
||||
match reader.read_to_string(&mut s).await {
|
||||
Ok(_) => Borrowed(Success(s)),
|
||||
Err(e) => Borrowed(Failure((Status::BadRequest, JsonError::Io(e))))
|
||||
}
|
||||
})
|
||||
|
|
|
@ -26,7 +26,7 @@ private-cookies = ["rocket_http/private-cookies"]
|
|||
[dependencies]
|
||||
rocket_codegen = { version = "0.5.0-dev", path = "../codegen" }
|
||||
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"
|
||||
yansi = "0.5"
|
||||
log = { version = "0.4", features = ["std"] }
|
||||
|
|
|
@ -142,7 +142,7 @@ pub type FromDataFuture<'a, T, E> = Pin<Box<dyn Future<Output = Outcome<T, E>> +
|
|||
/// if the guard returns successfully.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(proc_macro_hygiene)]
|
||||
/// # #![feature(proc_macro_hygiene, async_await)]
|
||||
/// # #[macro_use] extern crate rocket;
|
||||
/// # type DataGuard = rocket::data::Data;
|
||||
/// #[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`).
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(proc_macro_hygiene)]
|
||||
/// # #![feature(proc_macro_hygiene, async_await)]
|
||||
/// # #[macro_use] extern crate rocket;
|
||||
/// # #[derive(Debug)]
|
||||
/// # struct Name<'a> { first: &'a str, last: &'a str, }
|
||||
/// use std::io::{self, Read};
|
||||
///
|
||||
/// use futures::io::AsyncReadExt;
|
||||
///
|
||||
/// 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::AsyncReadExt as _;
|
||||
///
|
||||
/// const NAME_LIMIT: u64 = 256;
|
||||
///
|
||||
/// enum NameError {
|
||||
|
@ -210,32 +214,36 @@ pub type FromDataFuture<'a, T, E> = Pin<Box<dyn Future<Output = Outcome<T, E>> +
|
|||
/// type Owned = String;
|
||||
/// type Borrowed = str;
|
||||
///
|
||||
/// fn transform(_: &Request, data: Data) -> Transform<Outcome<Self::Owned, Self::Error>> {
|
||||
/// let mut stream = data.open().take(NAME_LIMIT);
|
||||
/// let mut string = String::with_capacity((NAME_LIMIT / 2) as usize);
|
||||
/// let outcome = match stream.read_to_string(&mut string) {
|
||||
/// Ok(_) => Success(string),
|
||||
/// Err(e) => Failure((Status::InternalServerError, NameError::Io(e)))
|
||||
/// };
|
||||
/// 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 string = String::with_capacity((NAME_LIMIT / 2) as usize);
|
||||
/// let outcome = match stream.read_to_string(&mut string).await {
|
||||
/// Ok(_) => Success(string),
|
||||
/// Err(e) => Failure((Status::InternalServerError, NameError::Io(e)))
|
||||
/// };
|
||||
///
|
||||
/// // Returning `Borrowed` here means we get `Borrowed` in `from_data`.
|
||||
/// Transform::Borrowed(outcome)
|
||||
/// // Returning `Borrowed` here means we get `Borrowed` in `from_data`.
|
||||
/// Transform::Borrowed(outcome)
|
||||
/// })
|
||||
/// }
|
||||
///
|
||||
/// fn from_data(_: &Request, outcome: Transformed<'a, Self>) -> Outcome<Self, Self::Error> {
|
||||
/// // Retrieve a borrow to the now transformed `String` (an &str). This
|
||||
/// // is only correct because we know we _always_ return a `Borrowed` from
|
||||
/// // `transform` above.
|
||||
/// let string = try_outcome!(outcome.borrowed());
|
||||
/// 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
|
||||
/// // is only correct because we know we _always_ return a `Borrowed` from
|
||||
/// // `transform` above.
|
||||
/// let string = try_outcome!(outcome.borrowed());
|
||||
///
|
||||
/// // Perform a crude, inefficient parse.
|
||||
/// let splits: Vec<&str> = string.split(" ").collect();
|
||||
/// if splits.len() != 2 || splits.iter().any(|s| s.is_empty()) {
|
||||
/// return Failure((Status::UnprocessableEntity, NameError::Parse));
|
||||
/// }
|
||||
/// // Perform a crude, inefficient parse.
|
||||
/// let splits: Vec<&str> = string.split(" ").collect();
|
||||
/// if splits.len() != 2 || splits.iter().any(|s| s.is_empty()) {
|
||||
/// return Failure((Status::UnprocessableEntity, NameError::Parse));
|
||||
/// }
|
||||
///
|
||||
/// // Return successfully.
|
||||
/// Success(Name { first: splits[0], last: splits[1] })
|
||||
/// // Return successfully.
|
||||
/// Success(Name { first: splits[0], last: splits[1] })
|
||||
/// })
|
||||
/// }
|
||||
/// }
|
||||
/// # #[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:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(proc_macro_hygiene)]
|
||||
/// # #![feature(proc_macro_hygiene, async_await)]
|
||||
/// # #[macro_use] extern crate rocket;
|
||||
/// # type Person = rocket::data::Data;
|
||||
/// #[post("/person", data = "<person>")]
|
||||
|
@ -447,7 +455,7 @@ impl<'a> FromData<'a> for Data {
|
|||
/// A `FromDataSimple` implementation allowing this looks like:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(proc_macro_hygiene)]
|
||||
/// # #![feature(proc_macro_hygiene, async_await)]
|
||||
/// # #[macro_use] extern crate rocket;
|
||||
/// #
|
||||
/// # #[derive(Debug)]
|
||||
|
@ -455,43 +463,50 @@ impl<'a> FromData<'a> for Data {
|
|||
/// #
|
||||
/// use std::io::Read;
|
||||
///
|
||||
/// use futures::io::AsyncReadExt;
|
||||
///
|
||||
/// use rocket::{Request, Data, Outcome, Outcome::*};
|
||||
/// use rocket::data::{self, FromDataSimple};
|
||||
/// use rocket::data::{self, FromDataSimple, FromDataFuture};
|
||||
/// use rocket::http::{Status, ContentType};
|
||||
///
|
||||
/// use rocket::AsyncReadExt as _;
|
||||
///
|
||||
/// // Always use a limit to prevent DoS attacks.
|
||||
/// const LIMIT: u64 = 256;
|
||||
///
|
||||
/// impl FromDataSimple for Person {
|
||||
/// 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.
|
||||
/// let person_ct = ContentType::new("application", "x-person");
|
||||
/// if req.content_type() != Some(&person_ct) {
|
||||
/// return Outcome::Forward(data);
|
||||
/// return Box::pin(async move { Outcome::Forward(data) });
|
||||
/// }
|
||||
///
|
||||
/// // Read the data into a String.
|
||||
/// let mut string = String::new();
|
||||
/// if let Err(e) = data.open().take(LIMIT).read_to_string(&mut string) {
|
||||
/// return Failure((Status::InternalServerError, format!("{:?}", e)));
|
||||
/// }
|
||||
/// Box::pin(async move {
|
||||
/// // Read the data into a String.
|
||||
/// let mut string = String::new();
|
||||
/// let mut reader = data.open().take(LIMIT);
|
||||
/// if let Err(e) = reader.read_to_string(&mut string).await {
|
||||
/// return Failure((Status::InternalServerError, format!("{:?}", e)));
|
||||
/// }
|
||||
///
|
||||
/// // Split the string into two pieces at ':'.
|
||||
/// let (name, age) = match string.find(':') {
|
||||
/// Some(i) => (string[..i].to_string(), &string[(i + 1)..]),
|
||||
/// None => return Failure((Status::UnprocessableEntity, "':'".into()))
|
||||
/// };
|
||||
/// // Split the string into two pieces at ':'.
|
||||
/// let (name, age) = match string.find(':') {
|
||||
/// Some(i) => (string[..i].to_string(), &string[(i + 1)..]),
|
||||
/// None => return Failure((Status::UnprocessableEntity, "':'".into()))
|
||||
/// };
|
||||
///
|
||||
/// // Parse the age.
|
||||
/// let age: u16 = match age.parse() {
|
||||
/// Ok(age) => age,
|
||||
/// Err(_) => return Failure((Status::UnprocessableEntity, "Age".into()))
|
||||
/// };
|
||||
/// // Parse the age.
|
||||
/// let age: u16 = match age.parse() {
|
||||
/// Ok(age) => age,
|
||||
/// Err(_) => return Failure((Status::UnprocessableEntity, "Age".into()))
|
||||
/// };
|
||||
///
|
||||
/// // Return successfully.
|
||||
/// Success(Person { name, age })
|
||||
/// // Return successfully.
|
||||
/// Success(Person { name, age })
|
||||
/// })
|
||||
/// }
|
||||
/// }
|
||||
/// # #[post("/person", data = "<person>")]
|
||||
|
@ -579,14 +594,11 @@ impl FromDataSimple for String {
|
|||
#[inline(always)]
|
||||
fn from_data(_: &Request<'_>, data: Data) -> FromDataFuture<'static, Self, Self::Error> {
|
||||
Box::pin(async {
|
||||
let mut stream = data.open();
|
||||
let mut buf = Vec::new();
|
||||
if let Err(e) = stream.read_to_end(&mut buf).await {
|
||||
return 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))),
|
||||
let mut string = String::new();
|
||||
let mut reader = data.open();
|
||||
match reader.read_to_string(&mut string).await {
|
||||
Ok(_) => Success(string),
|
||||
Err(e) => Failure((Status::BadRequest, e)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -196,6 +196,8 @@ impl<'f, T: FromForm<'f> + Send + 'f> FromData<'f> for Form<T> {
|
|||
request: &Request<'_>,
|
||||
data: Data
|
||||
) -> TransformFuture<'f, Self::Owned, Self::Error> {
|
||||
use std::cmp::min;
|
||||
|
||||
if !request.content_type().map_or(false, |ct| ct.is_form()) {
|
||||
warn_!("Form data does not have form content type.");
|
||||
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 mut stream = data.open().take(limit);
|
||||
Box::pin(async move {
|
||||
let mut buf = Vec::new();
|
||||
if let Err(e) = stream.read_to_end(&mut buf).await {
|
||||
let mut form_string = String::with_capacity(min(4096, limit) as usize);
|
||||
if let Err(e) = stream.read_to_string(&mut form_string).await {
|
||||
return Transform::Borrowed(Failure((Status::InternalServerError, FormDataError::Io(e))));
|
||||
}
|
||||
|
||||
Transform::Borrowed(match String::from_utf8(buf) {
|
||||
Ok(s) => Success(s),
|
||||
Err(e) => Failure((Status::BadRequest, FormDataError::Io(std::io::Error::new(std::io::ErrorKind::Other, e)))),
|
||||
})
|
||||
Transform::Borrowed(Success(form_string))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue