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