Eagerly read JSON data for deserialization.

Issue #547 identified a performance issue when serde's 'from_reader' is
used to deserialize incoming data. Using 'from_str' resolves the issue.
This commit swaps a use of 'from_reader' in favor of 'from_str' in
rocket_contrib's 'Json' implementation.

Additionally, this commit ensures that un-deserialized JSON data is
discarded as long as it is within the JSON data limit.

Closes #562.
This commit is contained in:
messense 2018-01-22 23:09:18 +08:00 committed by Sergio Benitez
parent d0f002c3d7
commit 6b608797a2
1 changed files with 17 additions and 1 deletions

View File

@ -15,6 +15,22 @@ use serde_json;
pub use serde_json::Value;
pub use serde_json::error::Error as SerdeError;
/// Like [`from_reader`] but eagerly reads the content of the reader to a string
/// and delegates to `from_str`.
///
/// [`from_reader`]: https://docs.serde.rs/serde_json/fn.from_reader.html
fn from_reader_eager<R, T>(mut reader: R) -> serde_json::Result<T>
where R: Read, T: DeserializeOwned
{
let mut s = String::new();
if let Err(io_err) = reader.read_to_string(&mut s) {
// Error::io is private to serde_json. Do not use outside of Rocket.
return Err(SerdeError::io(io_err));
}
serde_json::from_str(&s)
}
/// The JSON type: implements `FromData` and `Responder`, allowing you to easily
/// consume and respond with JSON.
///
@ -98,7 +114,7 @@ impl<T: DeserializeOwned> FromData for Json<T> {
}
let size_limit = request.limits().get("json").unwrap_or(LIMIT);
serde_json::from_reader(data.open().take(size_limit))
from_reader_eager(data.open().take(size_limit))
.map(|val| Json(val))
.map_err(|e| { error_!("Couldn't parse JSON body: {:?}", e); e })
.into_outcome(Status::BadRequest)