rocket_community/data/from_data.rs
1use crate::data::{Data, Limits};
2use crate::http::{RawStr, Status};
3use crate::outcome::{self, try_outcome, IntoOutcome, Outcome::*};
4use crate::request::{local_cache, Request};
5
6/// Type alias for the `Outcome` of [`FromData`].
7///
8/// [`FromData`]: crate::data::FromData
9pub type Outcome<'r, T, E = <T as FromData<'r>>::Error> =
10 outcome::Outcome<T, (Status, E), (Data<'r>, Status)>;
11
12/// Trait implemented by data guards to derive a value from request body data.
13///
14/// # Data Guards
15///
16/// A data guard is a guard that operates on a request's body data. Data guards
17/// validate and parse request body data via implementations of `FromData`. In
18/// other words, a type is a data guard _iff_ it implements `FromData`.
19///
20/// Data guards are the target of the `data` route attribute parameter:
21///
22/// ```rust
23/// # #[macro_use] extern crate rocket_community as rocket;
24/// # type DataGuard = String;
25/// #[post("/submit", data = "<var>")]
26/// fn submit(var: DataGuard) { /* ... */ }
27/// ```
28///
29/// A route can have at most one data guard. Above, `var` is used as the
30/// argument name for the data guard type `DataGuard`. When the `submit` route
31/// matches, Rocket will call the `FromData` implementation for the type `T`.
32/// The handler will only be called if the guard returns successfully.
33///
34/// ## Build-In Guards
35///
36/// Rocket provides implementations for `FromData` for many types. Their
37/// behavior is documented here:
38///
39/// * `Data`: Returns the untouched `Data`.
40///
41/// - **Fails:** Never.
42///
43/// - **Succeeds:** Always.
44///
45/// - **Forwards:** Never.
46///
47/// * Strings: `Cow<str>`, `&str`, `&RawStr`, `String`
48///
49/// _Limited by the `string` [data limit]._
50///
51/// Reads the body data into a string via [`DataStream::into_string()`].
52///
53/// - **Fails:** If the body data is not valid UTF-8 or on I/O errors while
54/// reading. The error type is [`io::Error`].
55///
56/// - **Succeeds:** If the body data _is_ valid UTF-8. If the limit is
57/// exceeded, the string is truncated to the limit.
58///
59/// - **Forwards:** Never.
60///
61/// * Bytes: `&[u8]`, `Vec<u8>`
62///
63/// _Limited by the `bytes` [data limit]._
64///
65/// Reads the body data into a byte vector via [`DataStream::into_bytes()`].
66///
67/// - **Fails:** On I/O errors while reading. The error type is
68/// [`io::Error`].
69///
70/// - **Succeeds:** As long as no I/O error occurs. If the limit is
71/// exceeded, the slice is truncated to the limit.
72///
73/// - **Forwards:** Never.
74///
75/// * [`TempFile`](crate::fs::TempFile)
76///
77/// _Limited by the `file` and/or `file/$ext` [data limit]._
78///
79/// Streams the body data directly into a temporary file. The data is never
80/// buffered in memory.
81///
82/// - **Fails:** On I/O errors while reading data or creating the temporary
83/// file. The error type is [`io::Error`].
84///
85/// - **Succeeds:** As long as no I/O error occurs and the temporary file
86/// could be created. If the limit is exceeded, only data up to the limit is
87/// read and subsequently written.
88///
89/// - **Forwards:** Never.
90///
91/// * Deserializers: [`Json<T>`], [`MsgPack<T>`]
92///
93/// _Limited by the `json`, `msgpack` [data limit], respectively._
94///
95/// Reads up to the configured limit and deserializes the read data into `T`
96/// using the respective format's parser.
97///
98/// - **Fails:** On I/O errors while reading the data, or if the data fails
99/// to parse as a `T` according to the deserializer. The error type for
100/// `Json` is [`json::Error`](crate::serde::json::Error) and the error type
101/// for `MsgPack` is [`msgpack::Error`](crate::serde::msgpack::Error).
102///
103/// - **Succeeds:** As long as no I/O error occurs and the (limited) body
104/// data was successfully deserialized as a `T`.
105///
106/// - **Forwards:** Never.
107///
108/// * Forms: [`Form<T>`]
109///
110/// _Limited by the `form` or `data-form` [data limit]._
111///
112/// Parses the incoming data stream into fields according to Rocket's [field
113/// wire format], pushes each field to `T`'s [`FromForm`] [push parser], and
114/// finalizes the form. Parsing is done on the stream without reading the
115/// data into memory. If the request has as a [`ContentType::Form`], the
116/// `form` limit is applied, otherwise if the request has a
117/// [`ContentType::FormData`], the `data-form` limit is applied.
118///
119/// - **Fails:** On I/O errors while reading the data, or if the data fails
120/// to parse as a `T` according to its `FromForm` implementation. The errors
121/// are collected into an [`Errors`](crate::form::Errors), the error type.
122///
123/// - **Succeeds:** As long as no I/O error occurs and the (limited) body
124/// data was successfully parsed as a `T`.
125///
126/// - **Forwards:** If the request's `Content-Type` is neither
127/// [`ContentType::Form`] nor [`ContentType::FormData`].
128///
129/// * `Option<T>`
130///
131/// Forwards to `T`'s `FromData` implementation, capturing the outcome.
132///
133/// - **Fails:** Never.
134///
135/// - **Succeeds:** Always. If `T`'s `FromData` implementation succeeds, the
136/// parsed value is returned in `Some`. If its implementation forwards or
137/// fails, `None` is returned.
138///
139/// - **Forwards:** Never.
140///
141/// * `Result<T, T::Error>`
142///
143/// Forwards to `T`'s `FromData` implementation, capturing the outcome.
144///
145/// - **Fails:** Never.
146///
147/// - **Succeeds:** If `T`'s `FromData` implementation succeeds or fails. If
148/// it succeeds, the value is returned in `Ok`. If it fails, the error value
149/// is returned in `Err`.
150///
151/// - **Forwards:** If `T`'s implementation forwards.
152///
153/// * [`Capped<T>`]
154///
155/// Forwards to `T`'s `FromData` implementation, recording whether the data
156/// was truncated (a.k.a. capped) due to `T`'s limit being exceeded.
157///
158/// - **Fails:** If `T`'s implementation fails.
159/// - **Succeeds:** If `T`'s implementation succeeds.
160/// - **Forwards:** If `T`'s implementation forwards.
161///
162/// [data limit]: crate::data::Limits#built-in-limits
163/// [`DataStream::into_string()`]: crate::data::DataStream::into_string()
164/// [`DataStream::into_bytes()`]: crate::data::DataStream::into_bytes()
165/// [`io::Error`]: std::io::Error
166/// [`Json<T>`]: crate::serde::json::Json
167/// [`MsgPack<T>`]: crate::serde::msgpack::MsgPack
168/// [`Form<T>`]: crate::form::Form
169/// [field wire format]: crate::form#field-wire-format
170/// [`FromForm`]: crate::form::FromForm
171/// [push parser]: crate::form::FromForm#push-parsing
172/// [`ContentType::Form`]: crate::http::ContentType::Form
173/// [`ContentType::FormData`]: crate::http::ContentType::FormData
174///
175/// ## Async Trait
176///
177/// [`FromData`] is an _async_ trait. Implementations of `FromData` must be
178/// decorated with an attribute of `#[rocket::async_trait]`:
179///
180/// ```rust
181/// # extern crate rocket_community as rocket;
182/// use rocket::request::Request;
183/// use rocket::data::{self, Data, FromData};
184/// # struct MyType;
185/// # type MyError = String;
186///
187/// #[rocket::async_trait]
188/// impl<'r> FromData<'r> for MyType {
189/// type Error = MyError;
190///
191/// async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> data::Outcome<'r, Self> {
192/// /* .. */
193/// # unimplemented!()
194/// }
195/// }
196/// ```
197///
198/// # Example
199///
200/// Say that you have a custom type, `Person`:
201///
202/// ```rust
203/// struct Person<'r> {
204/// name: &'r str,
205/// age: u16
206/// }
207/// ```
208///
209/// `Person` has a custom serialization format, so the built-in `Json` type
210/// doesn't suffice. The format is `<name>:<age>` with `Content-Type:
211/// application/x-person`. You'd like to use `Person` as a data guard, so that
212/// you can retrieve it directly from a client's request body:
213///
214/// ```rust
215/// # extern crate rocket_community as rocket;
216/// # use rocket::post;
217/// # type Person<'r> = &'r rocket::http::RawStr;
218/// #[post("/person", data = "<person>")]
219/// fn person(person: Person<'_>) -> &'static str {
220/// "Saved the new person to the database!"
221/// }
222/// ```
223///
224/// A `FromData` implementation for such a type might look like:
225///
226/// ```rust
227/// # #[macro_use] extern crate rocket_community as rocket;
228/// #
229/// # #[derive(Debug)]
230/// # struct Person<'r> { name: &'r str, age: u16 }
231/// #
232/// use rocket::request::{self, Request};
233/// use rocket::data::{self, Data, FromData, ToByteUnit};
234/// use rocket::http::{Status, ContentType};
235/// use rocket::outcome::Outcome;
236///
237/// #[derive(Debug)]
238/// enum Error {
239/// TooLarge,
240/// NoColon,
241/// InvalidAge,
242/// Io(std::io::Error),
243/// }
244///
245/// #[rocket::async_trait]
246/// impl<'r> FromData<'r> for Person<'r> {
247/// type Error = Error;
248///
249/// async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> data::Outcome<'r, Self> {
250/// use Error::*;
251///
252/// // Ensure the content type is correct before opening the data.
253/// let person_ct = ContentType::new("application", "x-person");
254/// if req.content_type() != Some(&person_ct) {
255/// return Outcome::Forward((data, Status::UnsupportedMediaType));
256/// }
257///
258/// // Use a configured limit with name 'person' or fallback to default.
259/// let limit = req.limits().get("person").unwrap_or(256.bytes());
260///
261/// // Read the data into a string.
262/// let string = match data.open(limit).into_string().await {
263/// Ok(string) if string.is_complete() => string.into_inner(),
264/// Ok(_) => return Outcome::Error((Status::PayloadTooLarge, TooLarge)),
265/// Err(e) => return Outcome::Error((Status::InternalServerError, Io(e))),
266/// };
267///
268/// // We store `string` in request-local cache for long-lived borrows.
269/// let string = request::local_cache!(req, string);
270///
271/// // Split the string into two pieces at ':'.
272/// let (name, age) = match string.find(':') {
273/// Some(i) => (&string[..i], &string[(i + 1)..]),
274/// None => return Outcome::Error((Status::UnprocessableEntity, NoColon)),
275/// };
276///
277/// // Parse the age.
278/// let age: u16 = match age.parse() {
279/// Ok(age) => age,
280/// Err(_) => return Outcome::Error((Status::UnprocessableEntity, InvalidAge)),
281/// };
282///
283/// Outcome::Success(Person { name, age })
284/// }
285/// }
286///
287/// // The following routes now typecheck...
288///
289/// #[post("/person", data = "<person>")]
290/// fn person(person: Person<'_>) { /* .. */ }
291///
292/// #[post("/person", data = "<person>")]
293/// fn person2(person: Result<Person<'_>, Error>) { /* .. */ }
294///
295/// #[post("/person", data = "<person>")]
296/// fn person3(person: Option<Person<'_>>) { /* .. */ }
297///
298/// #[post("/person", data = "<person>")]
299/// fn person4(person: Person<'_>) -> &str {
300/// // Note that this is only possible because the data in `person` live
301/// // as long as the request through request-local cache.
302/// person.name
303/// }
304/// ```
305#[crate::async_trait]
306pub trait FromData<'r>: Sized {
307 /// The associated error to be returned when the guard fails.
308 type Error: Send + std::fmt::Debug;
309
310 /// Asynchronously validates, parses, and converts an instance of `Self`
311 /// from the incoming request body data.
312 ///
313 /// If validation and parsing succeeds, an outcome of `Success` is returned.
314 /// If the data is not appropriate given the type of `Self`, `Forward` is
315 /// returned. If parsing fails, `Error` is returned.
316 async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self>;
317}
318
319use crate::data::Capped;
320
321#[crate::async_trait]
322impl<'r> FromData<'r> for Capped<String> {
323 type Error = std::io::Error;
324
325 async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
326 let limit = req.limits().get("string").unwrap_or(Limits::STRING);
327 data.open(limit)
328 .into_string()
329 .await
330 .or_error(Status::BadRequest)
331 }
332}
333
334impl_strict_from_data_from_capped!(String);
335
336#[crate::async_trait]
337impl<'r> FromData<'r> for Capped<&'r str> {
338 type Error = std::io::Error;
339
340 async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
341 let capped = try_outcome!(<Capped<String>>::from_data(req, data).await);
342 let string = capped.map(|s| local_cache!(req, s));
343 Success(string)
344 }
345}
346
347impl_strict_from_data_from_capped!(&'r str);
348
349#[crate::async_trait]
350impl<'r> FromData<'r> for Capped<&'r RawStr> {
351 type Error = std::io::Error;
352
353 async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
354 let capped = try_outcome!(<Capped<String>>::from_data(req, data).await);
355 let raw = capped.map(|s| RawStr::new(local_cache!(req, s)));
356 Success(raw)
357 }
358}
359
360impl_strict_from_data_from_capped!(&'r RawStr);
361
362#[crate::async_trait]
363impl<'r> FromData<'r> for Capped<std::borrow::Cow<'_, str>> {
364 type Error = std::io::Error;
365
366 async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
367 let capped = try_outcome!(<Capped<String>>::from_data(req, data).await);
368 Success(capped.map(|s| s.into()))
369 }
370}
371
372impl_strict_from_data_from_capped!(std::borrow::Cow<'_, str>);
373
374#[crate::async_trait]
375impl<'r> FromData<'r> for Capped<&'r [u8]> {
376 type Error = std::io::Error;
377
378 async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
379 let capped = try_outcome!(<Capped<Vec<u8>>>::from_data(req, data).await);
380 let raw = capped.map(|b| local_cache!(req, b));
381 Success(raw)
382 }
383}
384
385impl_strict_from_data_from_capped!(&'r [u8]);
386
387#[crate::async_trait]
388impl<'r> FromData<'r> for Capped<Vec<u8>> {
389 type Error = std::io::Error;
390
391 async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
392 let limit = req.limits().get("bytes").unwrap_or(Limits::BYTES);
393 data.open(limit)
394 .into_bytes()
395 .await
396 .or_error(Status::BadRequest)
397 }
398}
399
400impl_strict_from_data_from_capped!(Vec<u8>);
401
402#[crate::async_trait]
403impl<'r> FromData<'r> for Data<'r> {
404 type Error = std::convert::Infallible;
405
406 async fn from_data(_: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
407 Success(data)
408 }
409}
410
411#[crate::async_trait]
412impl<'r, T: FromData<'r> + 'r> FromData<'r> for Result<T, T::Error> {
413 type Error = std::convert::Infallible;
414
415 async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
416 match T::from_data(req, data).await {
417 Success(v) => Success(Ok(v)),
418 Error((_, e)) => Success(Err(e)),
419 Forward(d) => Forward(d),
420 }
421 }
422}
423
424#[crate::async_trait]
425impl<'r, T: FromData<'r>> FromData<'r> for Option<T> {
426 type Error = std::convert::Infallible;
427
428 async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
429 match T::from_data(req, data).await {
430 Success(v) => Success(Some(v)),
431 Error(..) | Forward(..) => Success(None),
432 }
433 }
434}