2016-09-19 23:24:01 +00:00
|
|
|
use std::ops::{Deref, DerefMut};
|
2018-09-19 01:30:25 +00:00
|
|
|
use std::io::{self, Read};
|
2016-09-19 23:24:01 +00:00
|
|
|
|
2017-04-19 04:52:02 +00:00
|
|
|
use rocket::outcome::{Outcome, IntoOutcome};
|
2016-10-25 11:24:07 +00:00
|
|
|
use rocket::request::Request;
|
|
|
|
use rocket::data::{self, Data, FromData};
|
2016-10-25 11:03:50 +00:00
|
|
|
use rocket::response::{self, Responder, content};
|
2016-12-15 08:47:31 +00:00
|
|
|
use rocket::http::Status;
|
2016-09-19 23:24:01 +00:00
|
|
|
|
2018-07-11 00:08:26 +00:00
|
|
|
use serde::{Serialize, Serializer};
|
|
|
|
use serde::de::{Deserialize, DeserializeOwned, Deserializer};
|
2017-02-01 01:15:42 +00:00
|
|
|
use serde_json;
|
2016-12-29 03:01:16 +00:00
|
|
|
|
2017-02-01 01:15:42 +00:00
|
|
|
/// The JSON type: implements `FromData` and `Responder`, allowing you to easily
|
|
|
|
/// consume and respond with JSON.
|
2016-09-19 23:24:01 +00:00
|
|
|
///
|
2017-04-18 07:36:39 +00:00
|
|
|
/// ## Receiving JSON
|
|
|
|
///
|
2017-02-09 08:16:13 +00:00
|
|
|
/// If you're receiving JSON data, simply add a `data` parameter to your route
|
2017-07-12 22:11:41 +00:00
|
|
|
/// arguments and ensure the type of the parameter is a `Json<T>`, where `T` is
|
2017-04-25 00:37:18 +00:00
|
|
|
/// some type you'd like to parse from JSON. `T` must implement `Deserialize` or
|
|
|
|
/// `DeserializeOwned` from [Serde](https://github.com/serde-rs/json). The data
|
|
|
|
/// is parsed from the HTTP request body.
|
2016-09-19 23:24:01 +00:00
|
|
|
///
|
|
|
|
/// ```rust,ignore
|
2016-10-12 07:14:42 +00:00
|
|
|
/// #[post("/users/", format = "application/json", data = "<user>")]
|
2017-07-12 22:11:41 +00:00
|
|
|
/// fn new_user(user: Json<User>) {
|
2016-09-19 23:24:01 +00:00
|
|
|
/// ...
|
|
|
|
/// }
|
|
|
|
/// ```
|
2017-01-31 18:36:37 +00:00
|
|
|
///
|
2016-09-19 23:24:01 +00:00
|
|
|
/// You don't _need_ to use `format = "application/json"`, but it _may_ be what
|
|
|
|
/// you want. Using `format = application/json` means that any request that
|
2017-02-09 08:16:13 +00:00
|
|
|
/// doesn't specify "application/json" as its `Content-Type` header value will
|
|
|
|
/// not be routed to the handler.
|
2016-09-19 23:24:01 +00:00
|
|
|
///
|
2017-04-18 07:36:39 +00:00
|
|
|
/// ## Sending JSON
|
|
|
|
///
|
2017-07-12 22:11:41 +00:00
|
|
|
/// If you're responding with JSON data, return a `Json<T>` type, where `T`
|
2016-10-12 07:14:42 +00:00
|
|
|
/// implements `Serialize` from [Serde](https://github.com/serde-rs/json). The
|
|
|
|
/// content type of the response is set to `application/json` automatically.
|
2016-09-19 23:24:01 +00:00
|
|
|
///
|
|
|
|
/// ```rust,ignore
|
|
|
|
/// #[get("/users/<id>")]
|
2017-07-12 22:11:41 +00:00
|
|
|
/// fn user(id: usize) -> Json<User> {
|
2016-09-19 23:24:01 +00:00
|
|
|
/// let user_from_id = User::from(id);
|
|
|
|
/// ...
|
2017-07-12 22:11:41 +00:00
|
|
|
/// Json(user_from_id)
|
2016-09-19 23:24:01 +00:00
|
|
|
/// }
|
|
|
|
/// ```
|
2017-04-18 07:36:39 +00:00
|
|
|
///
|
|
|
|
/// ## Incoming Data Limits
|
|
|
|
///
|
|
|
|
/// The default size limit for incoming JSON data is 1MiB. Setting a limit
|
|
|
|
/// protects your application from denial of service (DOS) attacks and from
|
|
|
|
/// resource exhaustion through high memory consumption. The limit can be
|
|
|
|
/// increased by setting the `limits.json` configuration parameter. For
|
|
|
|
/// instance, to increase the JSON limit to 5MiB for all environments, you may
|
|
|
|
/// add the following to your `Rocket.toml`:
|
|
|
|
///
|
|
|
|
/// ```toml
|
|
|
|
/// [global.limits]
|
|
|
|
/// json = 5242880
|
|
|
|
/// ```
|
2016-09-22 11:12:07 +00:00
|
|
|
#[derive(Debug)]
|
2017-08-26 06:14:42 +00:00
|
|
|
pub struct Json<T>(pub T);
|
2016-09-19 23:24:01 +00:00
|
|
|
|
2017-07-12 22:11:41 +00:00
|
|
|
impl<T> Json<T> {
|
2016-09-19 23:24:01 +00:00
|
|
|
/// Consumes the JSON wrapper and returns the wrapped item.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```rust
|
2017-07-12 22:11:41 +00:00
|
|
|
/// # use rocket_contrib::Json;
|
2016-09-19 23:24:01 +00:00
|
|
|
/// let string = "Hello".to_string();
|
2017-07-12 22:11:41 +00:00
|
|
|
/// let my_json = Json(string);
|
2017-01-15 11:00:46 +00:00
|
|
|
/// assert_eq!(my_json.into_inner(), "Hello".to_string());
|
2016-09-19 23:24:01 +00:00
|
|
|
/// ```
|
2017-05-19 10:29:08 +00:00
|
|
|
#[inline(always)]
|
2017-01-15 11:00:46 +00:00
|
|
|
pub fn into_inner(self) -> T {
|
2016-09-19 23:24:01 +00:00
|
|
|
self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-19 01:30:25 +00:00
|
|
|
/// 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) -> Result<T, JsonError>
|
|
|
|
where R: Read, T: DeserializeOwned
|
|
|
|
{
|
|
|
|
let mut s = String::with_capacity(512);
|
|
|
|
reader.read_to_string(&mut s).map_err(JsonError::Io)?;
|
|
|
|
|
|
|
|
serde_json::from_str(&s).map_err(|e| JsonError::Parse(s, e))
|
|
|
|
}
|
|
|
|
|
2017-04-18 07:25:13 +00:00
|
|
|
/// Default limit for JSON is 1MB.
|
|
|
|
const LIMIT: u64 = 1 << 20;
|
2016-10-12 07:14:42 +00:00
|
|
|
|
2018-09-19 01:30:25 +00:00
|
|
|
/// An error returned by the [`Json`] data guard when incoming data fails to
|
|
|
|
/// serialize as JSON.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum JsonError {
|
|
|
|
/// An I/O error occurred while reading the incoming request data.
|
|
|
|
Io(io::Error),
|
|
|
|
/// The client's data was received successfully but failed to parse as valid
|
|
|
|
/// JSON or as the requested type. The `String` value in `.0` is the raw
|
|
|
|
/// data received from the user, while the `Error` in `.1` is the
|
|
|
|
/// deserialization error from `serde`.
|
|
|
|
Parse(String, serde_json::error::Error),
|
|
|
|
}
|
|
|
|
|
2017-07-12 22:11:41 +00:00
|
|
|
impl<T: DeserializeOwned> FromData for Json<T> {
|
2018-09-19 01:30:25 +00:00
|
|
|
type Error = JsonError;
|
2016-10-12 07:14:42 +00:00
|
|
|
|
2018-09-19 01:30:25 +00:00
|
|
|
fn from_data(request: &Request, data: Data) -> data::Outcome<Self, Self::Error> {
|
2017-02-01 11:12:24 +00:00
|
|
|
if !request.content_type().map_or(false, |ct| ct.is_json()) {
|
2016-10-12 07:14:42 +00:00
|
|
|
error_!("Content-Type is not JSON.");
|
2016-10-25 11:03:50 +00:00
|
|
|
return Outcome::Forward(data);
|
2016-10-12 07:14:42 +00:00
|
|
|
}
|
|
|
|
|
2017-05-19 10:29:08 +00:00
|
|
|
let size_limit = request.limits().get("json").unwrap_or(LIMIT);
|
2018-01-22 15:09:18 +00:00
|
|
|
from_reader_eager(data.open().take(size_limit))
|
2018-07-28 16:58:10 +00:00
|
|
|
.map(Json)
|
2017-04-19 04:52:02 +00:00
|
|
|
.map_err(|e| { error_!("Couldn't parse JSON body: {:?}", e); e })
|
|
|
|
.into_outcome(Status::BadRequest)
|
2016-09-19 23:24:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-17 02:06:09 +00:00
|
|
|
/// Serializes the wrapped value into JSON. Returns a response with Content-Type
|
|
|
|
/// JSON and a fixed-size body with the serialized value. If serialization
|
|
|
|
/// fails, an `Err` of `Status::InternalServerError` is returned.
|
2018-09-19 01:30:25 +00:00
|
|
|
impl<'a, T: Serialize> Responder<'a> for Json<T> {
|
|
|
|
fn respond_to(self, req: &Request) -> response::Result<'a> {
|
2016-12-15 08:47:31 +00:00
|
|
|
serde_json::to_string(&self.0).map(|string| {
|
2017-07-12 22:21:45 +00:00
|
|
|
content::Json(string).respond_to(req).unwrap()
|
2016-12-15 08:47:31 +00:00
|
|
|
}).map_err(|e| {
|
|
|
|
error_!("JSON failed to serialize: {:?}", e);
|
2016-12-23 10:38:30 +00:00
|
|
|
Status::InternalServerError
|
2016-12-15 08:47:31 +00:00
|
|
|
})
|
2016-09-19 23:24:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-12 22:11:41 +00:00
|
|
|
impl<T> Deref for Json<T> {
|
2016-09-19 23:24:01 +00:00
|
|
|
type Target = T;
|
|
|
|
|
2017-05-19 10:29:08 +00:00
|
|
|
#[inline(always)]
|
2018-07-28 16:58:10 +00:00
|
|
|
fn deref(&self) -> &T {
|
2016-09-19 23:24:01 +00:00
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-12 22:11:41 +00:00
|
|
|
impl<T> DerefMut for Json<T> {
|
2017-05-19 10:29:08 +00:00
|
|
|
#[inline(always)]
|
2018-07-28 16:58:10 +00:00
|
|
|
fn deref_mut(&mut self) -> &mut T {
|
2016-09-19 23:24:01 +00:00
|
|
|
&mut self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-26 06:14:42 +00:00
|
|
|
/// An arbitrary JSON value.
|
|
|
|
///
|
|
|
|
/// This structure wraps `serde`'s [`Value`] type. Importantly, unlike `Value`,
|
|
|
|
/// this type implements [`Responder`], allowing a value of this type to be
|
|
|
|
/// returned directly from a handler.
|
|
|
|
///
|
|
|
|
/// [`Value`]: https://docs.rs/serde_json/1.0.2/serde_json/value/enum.Value.html
|
|
|
|
/// [`Responder`]: /rocket/response/trait.Responder.html
|
|
|
|
///
|
|
|
|
/// # `Responder`
|
|
|
|
///
|
|
|
|
/// The `Responder` implementation for `JsonValue` serializes the represented
|
|
|
|
/// value into a JSON string and sets the string as the body of a fixed-sized
|
|
|
|
/// response with a `Content-Type` of `application/json`.
|
|
|
|
///
|
|
|
|
/// # Usage
|
|
|
|
///
|
|
|
|
/// A value of this type is constructed via the
|
|
|
|
/// [`json!`](/rocket_contrib/macro.json.html) macro. The macro and this type
|
|
|
|
/// are typically used to construct JSON values in an ad-hoc fashion during
|
|
|
|
/// request handling. This looks something like:
|
|
|
|
///
|
|
|
|
/// ```rust,ignore
|
|
|
|
/// use rocket_contrib::JsonValue;
|
|
|
|
///
|
|
|
|
/// #[get("/item")]
|
|
|
|
/// fn get_item() -> JsonValue {
|
|
|
|
/// json!({
|
|
|
|
/// "id": 83,
|
|
|
|
/// "values": [1, 2, 3, 4]
|
|
|
|
/// })
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
#[derive(Debug, Clone, PartialEq, Default)]
|
|
|
|
pub struct JsonValue(pub serde_json::Value);
|
|
|
|
|
2018-07-11 00:08:26 +00:00
|
|
|
impl Serialize for JsonValue {
|
|
|
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
|
|
|
self.0.serialize(serializer)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'de> Deserialize<'de> for JsonValue {
|
|
|
|
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
|
|
|
serde_json::Value::deserialize(deserializer).map(JsonValue)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-26 06:14:42 +00:00
|
|
|
impl JsonValue {
|
|
|
|
#[inline(always)]
|
|
|
|
fn into_inner(self) -> serde_json::Value {
|
|
|
|
self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Deref for JsonValue {
|
|
|
|
type Target = serde_json::Value;
|
|
|
|
|
|
|
|
#[inline(always)]
|
2018-07-28 16:58:10 +00:00
|
|
|
fn deref(&self) -> &Self::Target {
|
2017-08-26 06:14:42 +00:00
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DerefMut for JsonValue {
|
|
|
|
#[inline(always)]
|
2018-07-28 16:58:10 +00:00
|
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
2017-08-26 06:14:42 +00:00
|
|
|
&mut self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Into<serde_json::Value> for JsonValue {
|
|
|
|
#[inline(always)]
|
|
|
|
fn into(self) -> serde_json::Value {
|
|
|
|
self.into_inner()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<serde_json::Value> for JsonValue {
|
|
|
|
#[inline(always)]
|
|
|
|
fn from(value: serde_json::Value) -> JsonValue {
|
|
|
|
JsonValue(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Serializes the value into JSON. Returns a response with Content-Type JSON
|
|
|
|
/// and a fixed-size body with the serialized value.
|
|
|
|
impl<'a> Responder<'a> for JsonValue {
|
|
|
|
#[inline]
|
|
|
|
fn respond_to(self, req: &Request) -> response::Result<'a> {
|
|
|
|
content::Json(self.0.to_string()).respond_to(req)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-01 01:15:42 +00:00
|
|
|
/// A macro to create ad-hoc JSON serializable values using JSON syntax.
|
|
|
|
///
|
|
|
|
/// # Usage
|
|
|
|
///
|
|
|
|
/// To import the macro, add the `#[macro_use]` attribute to the `extern crate
|
|
|
|
/// rocket_contrib` invocation:
|
|
|
|
///
|
|
|
|
/// ```rust,ignore
|
|
|
|
/// #[macro_use] extern crate rocket_contrib;
|
|
|
|
/// ```
|
|
|
|
///
|
2017-08-26 06:14:42 +00:00
|
|
|
/// The return type of a `json!` invocation is
|
|
|
|
/// [`JsonValue`](/rocket_contrib/struct.JsonValue.html). A value created with
|
|
|
|
/// this macro can be returned from a handler as follows:
|
2016-09-19 23:24:01 +00:00
|
|
|
///
|
2017-02-01 01:15:42 +00:00
|
|
|
/// ```rust,ignore
|
2017-08-26 06:14:42 +00:00
|
|
|
/// use rocket_contrib::JsonValue;
|
2017-02-01 01:15:42 +00:00
|
|
|
///
|
|
|
|
/// #[get("/json")]
|
2017-08-26 06:14:42 +00:00
|
|
|
/// fn get_json() -> JsonValue {
|
|
|
|
/// json!({
|
2017-02-01 01:15:42 +00:00
|
|
|
/// "key": "value",
|
|
|
|
/// "array": [1, 2, 3, 4]
|
2017-08-26 06:14:42 +00:00
|
|
|
/// })
|
2017-02-01 01:15:42 +00:00
|
|
|
/// }
|
|
|
|
/// ```
|
2016-12-29 03:01:16 +00:00
|
|
|
///
|
2017-08-26 06:14:42 +00:00
|
|
|
/// The `Responder` implementation for `JsonValue` serializes the value into a
|
|
|
|
/// JSON string and sets it as the body of the response with a `Content-Type` of
|
|
|
|
/// `application/json`.
|
|
|
|
///
|
2016-09-19 23:24:01 +00:00
|
|
|
/// # Examples
|
|
|
|
///
|
2017-02-01 01:15:42 +00:00
|
|
|
/// Create a simple JSON object with two keys: `"username"` and `"id"`:
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # #![allow(unused_variables)]
|
|
|
|
/// # #[macro_use] extern crate rocket_contrib;
|
|
|
|
/// # fn main() {
|
|
|
|
/// let value = json!({
|
|
|
|
/// "username": "mjordan",
|
|
|
|
/// "id": 23
|
|
|
|
/// });
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Create a more complex object with a nested object and array:
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # #![allow(unused_variables)]
|
|
|
|
/// # #[macro_use] extern crate rocket_contrib;
|
|
|
|
/// # fn main() {
|
|
|
|
/// let value = json!({
|
|
|
|
/// "code": 200,
|
|
|
|
/// "success": true,
|
|
|
|
/// "payload": {
|
|
|
|
/// "features": ["serde", "json"],
|
|
|
|
/// "ids": [12, 121],
|
|
|
|
/// },
|
|
|
|
/// });
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Variables or expressions can be interpolated into the JSON literal. Any type
|
2018-07-12 03:44:09 +00:00
|
|
|
/// interpolated into an array element or object value must implement serde's
|
2017-02-01 01:15:42 +00:00
|
|
|
/// `Serialize` trait, while any type interpolated into a object key must
|
|
|
|
/// implement `Into<String>`.
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # #![allow(unused_variables)]
|
|
|
|
/// # #[macro_use] extern crate rocket_contrib;
|
|
|
|
/// # fn main() {
|
|
|
|
/// let code = 200;
|
|
|
|
/// let features = vec!["serde", "json"];
|
|
|
|
///
|
|
|
|
/// let value = json!({
|
|
|
|
/// "code": code,
|
|
|
|
/// "success": code == 200,
|
|
|
|
/// "payload": {
|
|
|
|
/// features[0]: features[1]
|
|
|
|
/// }
|
|
|
|
/// });
|
|
|
|
/// # }
|
2016-09-19 23:24:01 +00:00
|
|
|
/// ```
|
2017-02-01 01:15:42 +00:00
|
|
|
///
|
|
|
|
/// Trailing commas are allowed inside both arrays and objects.
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # #![allow(unused_variables)]
|
2016-09-19 23:24:01 +00:00
|
|
|
/// # #[macro_use] extern crate rocket_contrib;
|
|
|
|
/// # fn main() {
|
2017-02-01 01:15:42 +00:00
|
|
|
/// let value = json!([
|
|
|
|
/// "notice",
|
|
|
|
/// "the",
|
|
|
|
/// "trailing",
|
|
|
|
/// "comma -->",
|
|
|
|
/// ]);
|
2016-09-19 23:24:01 +00:00
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[macro_export]
|
2017-02-01 01:15:42 +00:00
|
|
|
macro_rules! json {
|
|
|
|
($($json:tt)+) => {
|
2017-08-26 06:14:42 +00:00
|
|
|
$crate::JsonValue(json_internal!($($json)+))
|
2016-09-19 23:24:01 +00:00
|
|
|
};
|
|
|
|
}
|