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