rocket/serde/
msgpack.rs

1//! Automatic MessagePack (de)serialization support.
2//!
3//! See [`MsgPack`] for further details.
4//!
5//! # Enabling
6//!
7//! This module is only available when the `msgpack` feature is enabled. Enable
8//! it in `Cargo.toml` as follows:
9//!
10//! ```toml
11//! [dependencies.rocket]
12//! version = "0.5.1"
13//! features = ["msgpack"]
14//! ```
15//!
16//! # Testing
17//!
18//! The [`LocalRequest`] and [`LocalResponse`] types provide [`msgpack()`] and
19//! [`into_msgpack()`] methods to create a request with serialized MessagePack
20//! and deserialize a response as MessagePack, respectively.
21//!
22//! [`LocalRequest`]: crate::local::blocking::LocalRequest
23//! [`LocalResponse`]: crate::local::blocking::LocalResponse
24//! [`msgpack()`]: crate::local::blocking::LocalRequest::msgpack()
25//! [`into_msgpack()`]: crate::local::blocking::LocalResponse::into_msgpack()
26
27use std::io;
28use std::ops::{Deref, DerefMut};
29
30use crate::request::{Request, local_cache};
31use crate::data::{Limits, Data, FromData, Outcome};
32use crate::response::{self, Responder, content};
33use crate::http::Status;
34use crate::form::prelude as form;
35// use crate::http::uri::fmt;
36
37use serde::{Serialize, Deserialize};
38
39#[doc(inline)]
40pub use rmp_serde::decode::Error;
41
42/// The MessagePack guard: easily consume and return MessagePack.
43///
44/// ## Sending MessagePack
45///
46/// To respond with serialized MessagePack data, return a `MsgPack<T>` type,
47/// where `T` implements [`Serialize`] from [`serde`]. The content type of the
48/// response is set to `application/msgpack` automatically.
49///
50/// ```rust
51/// # #[macro_use] extern crate rocket;
52/// # type User = usize;
53/// use rocket::serde::msgpack::MsgPack;
54///
55/// #[get("/users/<id>")]
56/// fn user(id: usize) -> MsgPack<User> {
57///     let user_from_id = User::from(id);
58///     /* ... */
59///     MsgPack(user_from_id)
60/// }
61/// ```
62///
63/// ## Receiving MessagePack
64///
65/// `MsgPack` is both a data guard and a form guard.
66///
67/// ### Data Guard
68///
69/// To deserialize request body data as MessagePack, add a `data` route
70/// argument with a target type of `MsgPack<T>`, where `T` is some type you'd
71/// like to parse from JSON. `T` must implement [`serde::Deserialize`].
72///
73/// ```rust
74/// # #[macro_use] extern crate rocket;
75/// # type User = usize;
76/// use rocket::serde::msgpack::MsgPack;
77///
78/// #[post("/users", format = "msgpack", data = "<user>")]
79/// fn new_user(user: MsgPack<User>) {
80///     /* ... */
81/// }
82/// ```
83///
84/// You don't _need_ to use `format = "msgpack"`, but it _may_ be what you want.
85/// Using `format = msgpack` means that any request that doesn't specify
86/// "application/msgpack" as its first `Content-Type:` header parameter will not
87/// be routed to this handler.
88///
89/// ### Form Guard
90///
91/// `MsgPack<T>`, as a form guard, accepts value and data fields and parses the
92/// data as a `T`. Simple use `MsgPack<T>`:
93///
94/// ```rust
95/// # #[macro_use] extern crate rocket;
96/// # type Metadata = usize;
97/// use rocket::form::{Form, FromForm};
98/// use rocket::serde::msgpack::MsgPack;
99///
100/// #[derive(FromForm)]
101/// struct User<'r> {
102///     name: &'r str,
103///     metadata: MsgPack<Metadata>
104/// }
105///
106/// #[post("/users", data = "<form>")]
107/// fn new_user(form: Form<User<'_>>) {
108///     /* ... */
109/// }
110/// ```
111///
112/// ### Incoming Data Limits
113///
114/// The default size limit for incoming MessagePack data is 1MiB. Setting a
115/// limit protects your application from denial of service (DOS) attacks and
116/// from resource exhaustion through high memory consumption. The limit can be
117/// increased by setting the `limits.msgpack` configuration parameter. For
118/// instance, to increase the MessagePack limit to 5MiB for all environments,
119/// you may add the following to your `Rocket.toml`:
120///
121/// ```toml
122/// [global.limits]
123/// msgpack = 5242880
124/// ```
125#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
126pub struct MsgPack<T>(pub T);
127
128impl<T> MsgPack<T> {
129    /// Consumes the `MsgPack` wrapper and returns the wrapped item.
130    ///
131    /// # Example
132    ///
133    /// ```rust
134    /// # use rocket::serde::msgpack::MsgPack;
135    /// let string = "Hello".to_string();
136    /// let my_msgpack = MsgPack(string);
137    /// assert_eq!(my_msgpack.into_inner(), "Hello".to_string());
138    /// ```
139    #[inline(always)]
140    pub fn into_inner(self) -> T {
141        self.0
142    }
143}
144
145impl<'r, T: Deserialize<'r>> MsgPack<T> {
146    fn from_bytes(buf: &'r [u8]) -> Result<Self, Error> {
147        rmp_serde::from_slice(buf).map(MsgPack)
148    }
149
150    async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Result<Self, Error> {
151        let limit = req.limits().get("msgpack").unwrap_or(Limits::MESSAGE_PACK);
152        let bytes = match data.open(limit).into_bytes().await {
153            Ok(buf) if buf.is_complete() => buf.into_inner(),
154            Ok(_) => {
155                let eof = io::ErrorKind::UnexpectedEof;
156                return Err(Error::InvalidDataRead(io::Error::new(eof, "data limit exceeded")));
157            },
158            Err(e) => return Err(Error::InvalidDataRead(e)),
159        };
160
161        Self::from_bytes(local_cache!(req, bytes))
162    }
163}
164
165#[crate::async_trait]
166impl<'r, T: Deserialize<'r>> FromData<'r> for MsgPack<T> {
167    type Error = Error;
168
169    async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
170        match Self::from_data(req, data).await {
171            Ok(value) => Outcome::Success(value),
172            Err(Error::InvalidDataRead(e)) if e.kind() == io::ErrorKind::UnexpectedEof => {
173                Outcome::Error((Status::PayloadTooLarge, Error::InvalidDataRead(e)))
174            },
175            | Err(e@Error::TypeMismatch(_))
176            | Err(e@Error::OutOfRange)
177            | Err(e@Error::LengthMismatch(_))
178            => {
179                Outcome::Error((Status::UnprocessableEntity, e))
180            },
181            Err(e) => Outcome::Error((Status::BadRequest, e)),
182        }
183    }
184}
185
186/// Serializes the wrapped value into MessagePack. Returns a response with
187/// Content-Type `MsgPack` and a fixed-size body with the serialization. If
188/// serialization fails, an `Err` of `Status::InternalServerError` is returned.
189impl<'r, T: Serialize> Responder<'r, 'static> for MsgPack<T> {
190    fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> {
191        let buf = rmp_serde::to_vec(&self.0)
192            .map_err(|e| {
193                error_!("MsgPack failed to serialize: {:?}", e);
194                Status::InternalServerError
195            })?;
196
197        content::RawMsgPack(buf).respond_to(req)
198    }
199}
200
201#[crate::async_trait]
202impl<'v, T: Deserialize<'v> + Send> form::FromFormField<'v> for MsgPack<T> {
203    // TODO: To implement `from_value`, we need to the raw string so we can
204    // decode it into bytes as opposed to a string as it won't be UTF-8.
205
206    async fn from_data(f: form::DataField<'v, '_>) -> Result<Self, form::Errors<'v>> {
207        Self::from_data(f.request, f.data).await.map_err(|e| {
208            match e {
209                Error::InvalidMarkerRead(e) | Error::InvalidDataRead(e) => e.into(),
210                Error::Utf8Error(e) => e.into(),
211                _ => form::Error::custom(e).into(),
212            }
213        })
214    }
215}
216
217// impl<T: Serialize> fmt::UriDisplay<fmt::Query> for MsgPack<T> {
218//     fn fmt(&self, f: &mut fmt::Formatter<'_, fmt::Query>) -> std::fmt::Result {
219//         let bytes = to_vec(&self.0).map_err(|_| std::fmt::Error)?;
220//         let encoded = crate::http::RawStr::percent_encode_bytes(&bytes);
221//         f.write_value(encoded.as_str())
222//     }
223// }
224
225impl<T> From<T> for MsgPack<T> {
226    fn from(value: T) -> Self {
227        MsgPack(value)
228    }
229}
230
231impl<T> Deref for MsgPack<T> {
232    type Target = T;
233
234    #[inline(always)]
235    fn deref(&self) -> &T {
236        &self.0
237    }
238}
239
240impl<T> DerefMut for MsgPack<T> {
241    #[inline(always)]
242    fn deref_mut(&mut self) -> &mut T {
243        &mut self.0
244    }
245}
246
247/// Deserialize an instance of type `T` from MessagePack encoded bytes.
248///
249/// Deserialization is performed in a zero-copy manner whenever possible.
250///
251/// **_Always_ use [`MsgPack`] to deserialize MessagePack request data.**
252///
253/// # Example
254///
255/// ```
256/// use rocket::serde::{Deserialize, msgpack};
257///
258/// #[derive(Debug, PartialEq, Deserialize)]
259/// #[serde(crate = "rocket::serde")]
260/// struct Data<'r> {
261///     framework: &'r str,
262///     stars: usize,
263/// }
264///
265/// let bytes = &[
266///     130, 169, 102, 114, 97, 109, 101, 119, 111, 114, 107, 166, 82, 111,
267///     99, 107, 101, 116, 165, 115, 116, 97, 114, 115, 5
268/// ];
269///
270/// let data: Data = msgpack::from_slice(bytes).unwrap();
271/// assert_eq!(data, Data { framework: "Rocket", stars: 5, });
272/// ```
273///
274/// # Errors
275///
276/// Deserialization fails if `v` does not represent a valid MessagePack encoding
277/// of any instance of `T` or if `T`'s `Deserialize` implementation fails
278/// otherwise.
279#[inline(always)]
280pub fn from_slice<'a, T>(v: &'a [u8]) -> Result<T, Error>
281    where T: Deserialize<'a>,
282{
283    rmp_serde::from_slice(v)
284}
285
286/// Serialize a `T` into a MessagePack byte vector with compact representation.
287///
288/// The compact representation represents structs as arrays.
289///
290/// **_Always_ use [`MsgPack`] to serialize MessagePack response data.**
291///
292/// # Example
293///
294/// ```
295/// use rocket::serde::{Deserialize, Serialize, msgpack};
296///
297/// #[derive(Deserialize, Serialize)]
298/// #[serde(crate = "rocket::serde")]
299/// struct Data<'r> {
300///     framework: &'r str,
301///     stars: usize,
302/// }
303///
304/// let bytes = &[146, 166, 82, 111, 99, 107, 101, 116, 5];
305/// let data: Data = msgpack::from_slice(bytes).unwrap();
306/// let byte_vec = msgpack::to_compact_vec(&data).unwrap();
307/// assert_eq!(bytes, &byte_vec[..]);
308/// ```
309///
310/// # Errors
311///
312/// Serialization fails if `T`'s `Serialize` implementation fails.
313#[inline(always)]
314pub fn to_compact_vec<T>(value: &T) -> Result<Vec<u8>, rmp_serde::encode::Error>
315    where T: Serialize + ?Sized
316{
317    rmp_serde::to_vec(value)
318}
319
320/// Serialize a `T` into a MessagePack byte vector with named representation.
321///
322/// The named representation represents structs as maps with field names.
323///
324/// **_Always_ use [`MsgPack`] to serialize MessagePack response data.**
325///
326/// # Example
327///
328/// ```
329/// use rocket::serde::{Deserialize, Serialize, msgpack};
330///
331/// #[derive(Deserialize, Serialize)]
332/// #[serde(crate = "rocket::serde")]
333/// struct Data<'r> {
334///     framework: &'r str,
335///     stars: usize,
336/// }
337///
338/// let bytes = &[
339///     130, 169, 102, 114, 97, 109, 101, 119, 111, 114, 107, 166, 82, 111,
340///     99, 107, 101, 116, 165, 115, 116, 97, 114, 115, 5
341/// ];
342///
343/// let data: Data = msgpack::from_slice(bytes).unwrap();
344/// let byte_vec = msgpack::to_vec(&data).unwrap();
345/// assert_eq!(bytes, &byte_vec[..]);
346/// ```
347///
348/// # Errors
349///
350/// Serialization fails if `T`'s `Serialize` implementation fails.
351#[inline(always)]
352pub fn to_vec<T>(value: &T) -> Result<Vec<u8>, rmp_serde::encode::Error>
353    where T: Serialize + ?Sized
354{
355    rmp_serde::to_vec_named(value)
356}