From ae8e9025d21c8ff512d8a0917494e21b9eaafc2e Mon Sep 17 00:00:00 2001 From: messense Date: Mon, 22 Jan 2018 23:09:18 +0800 Subject: [PATCH] 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. --- contrib/src/json.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/contrib/src/json.rs b/contrib/src/json.rs index 2eb36680..38b2f64d 100644 --- a/contrib/src/json.rs +++ b/contrib/src/json.rs @@ -14,6 +14,22 @@ use serde_json; 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(mut reader: R) -> serde_json::Result + 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. /// @@ -97,7 +113,7 @@ impl FromData for Json { } 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)