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}