rocket/data/from_data.rs
1use crate::http::{RawStr, Status};
2use crate::request::{Request, local_cache};
3use crate::data::{Data, Limits};
4use crate::outcome::{self, IntoOutcome, try_outcome, Outcome::*};
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;
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/// use rocket::request::Request;
182/// use rocket::data::{self, Data, FromData};
183/// # struct MyType;
184/// # type MyError = String;
185///
186/// #[rocket::async_trait]
187/// impl<'r> FromData<'r> for MyType {
188/// type Error = MyError;
189///
190/// async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> data::Outcome<'r, Self> {
191/// /* .. */
192/// # unimplemented!()
193/// }
194/// }
195/// ```
196///
197/// # Example
198///
199/// Say that you have a custom type, `Person`:
200///
201/// ```rust
202/// struct Person<'r> {
203/// name: &'r str,
204/// age: u16
205/// }
206/// ```
207///
208/// `Person` has a custom serialization format, so the built-in `Json` type
209/// doesn't suffice. The format is `<name>:<age>` with `Content-Type:
210/// application/x-person`. You'd like to use `Person` as a data guard, so that
211/// you can retrieve it directly from a client's request body:
212///
213/// ```rust
214/// # use rocket::post;
215/// # type Person<'r> = &'r rocket::http::RawStr;
216/// #[post("/person", data = "<person>")]
217/// fn person(person: Person<'_>) -> &'static str {
218/// "Saved the new person to the database!"
219/// }
220/// ```
221///
222/// A `FromData` implementation for such a type might look like:
223///
224/// ```rust
225/// # #[macro_use] extern crate rocket;
226/// #
227/// # #[derive(Debug)]
228/// # struct Person<'r> { name: &'r str, age: u16 }
229/// #
230/// use rocket::request::{self, Request};
231/// use rocket::data::{self, Data, FromData, ToByteUnit};
232/// use rocket::http::{Status, ContentType};
233/// use rocket::outcome::Outcome;
234///
235/// #[derive(Debug)]
236/// enum Error {
237/// TooLarge,
238/// NoColon,
239/// InvalidAge,
240/// Io(std::io::Error),
241/// }
242///
243/// #[rocket::async_trait]
244/// impl<'r> FromData<'r> for Person<'r> {
245/// type Error = Error;
246///
247/// async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> data::Outcome<'r, Self> {
248/// use Error::*;
249///
250/// // Ensure the content type is correct before opening the data.
251/// let person_ct = ContentType::new("application", "x-person");
252/// if req.content_type() != Some(&person_ct) {
253/// return Outcome::Forward((data, Status::UnsupportedMediaType));
254/// }
255///
256/// // Use a configured limit with name 'person' or fallback to default.
257/// let limit = req.limits().get("person").unwrap_or(256.bytes());
258///
259/// // Read the data into a string.
260/// let string = match data.open(limit).into_string().await {
261/// Ok(string) if string.is_complete() => string.into_inner(),
262/// Ok(_) => return Outcome::Error((Status::PayloadTooLarge, TooLarge)),
263/// Err(e) => return Outcome::Error((Status::InternalServerError, Io(e))),
264/// };
265///
266/// // We store `string` in request-local cache for long-lived borrows.
267/// let string = request::local_cache!(req, string);
268///
269/// // Split the string into two pieces at ':'.
270/// let (name, age) = match string.find(':') {
271/// Some(i) => (&string[..i], &string[(i + 1)..]),
272/// None => return Outcome::Error((Status::UnprocessableEntity, NoColon)),
273/// };
274///
275/// // Parse the age.
276/// let age: u16 = match age.parse() {
277/// Ok(age) => age,
278/// Err(_) => return Outcome::Error((Status::UnprocessableEntity, InvalidAge)),
279/// };
280///
281/// Outcome::Success(Person { name, age })
282/// }
283/// }
284///
285/// // The following routes now typecheck...
286///
287/// #[post("/person", data = "<person>")]
288/// fn person(person: Person<'_>) { /* .. */ }
289///
290/// #[post("/person", data = "<person>")]
291/// fn person2(person: Result<Person<'_>, Error>) { /* .. */ }
292///
293/// #[post("/person", data = "<person>")]
294/// fn person3(person: Option<Person<'_>>) { /* .. */ }
295///
296/// #[post("/person", data = "<person>")]
297/// fn person4(person: Person<'_>) -> &str {
298/// // Note that this is only possible because the data in `person` live
299/// // as long as the request through request-local cache.
300/// person.name
301/// }
302/// ```
303#[crate::async_trait]
304pub trait FromData<'r>: Sized {
305 /// The associated error to be returned when the guard fails.
306 type Error: Send + std::fmt::Debug;
307
308 /// Asynchronously validates, parses, and converts an instance of `Self`
309 /// from the incoming request body data.
310 ///
311 /// If validation and parsing succeeds, an outcome of `Success` is returned.
312 /// If the data is not appropriate given the type of `Self`, `Forward` is
313 /// returned. If parsing fails, `Error` is returned.
314 async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self>;
315}
316
317use crate::data::Capped;
318
319#[crate::async_trait]
320impl<'r> FromData<'r> for Capped<String> {
321 type Error = std::io::Error;
322
323 async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
324 let limit = req.limits().get("string").unwrap_or(Limits::STRING);
325 data.open(limit).into_string().await.or_error(Status::BadRequest)
326 }
327}
328
329impl_strict_from_data_from_capped!(String);
330
331#[crate::async_trait]
332impl<'r> FromData<'r> for Capped<&'r str> {
333 type Error = std::io::Error;
334
335 async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
336 let capped = try_outcome!(<Capped<String>>::from_data(req, data).await);
337 let string = capped.map(|s| local_cache!(req, s));
338 Success(string)
339 }
340}
341
342impl_strict_from_data_from_capped!(&'r str);
343
344#[crate::async_trait]
345impl<'r> FromData<'r> for Capped<&'r RawStr> {
346 type Error = std::io::Error;
347
348 async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
349 let capped = try_outcome!(<Capped<String>>::from_data(req, data).await);
350 let raw = capped.map(|s| RawStr::new(local_cache!(req, s)));
351 Success(raw)
352 }
353}
354
355impl_strict_from_data_from_capped!(&'r RawStr);
356
357#[crate::async_trait]
358impl<'r> FromData<'r> for Capped<std::borrow::Cow<'_, str>> {
359 type Error = std::io::Error;
360
361 async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
362 let capped = try_outcome!(<Capped<String>>::from_data(req, data).await);
363 Success(capped.map(|s| s.into()))
364 }
365}
366
367impl_strict_from_data_from_capped!(std::borrow::Cow<'_, str>);
368
369#[crate::async_trait]
370impl<'r> FromData<'r> for Capped<&'r [u8]> {
371 type Error = std::io::Error;
372
373 async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
374 let capped = try_outcome!(<Capped<Vec<u8>>>::from_data(req, data).await);
375 let raw = capped.map(|b| local_cache!(req, b));
376 Success(raw)
377 }
378}
379
380impl_strict_from_data_from_capped!(&'r [u8]);
381
382#[crate::async_trait]
383impl<'r> FromData<'r> for Capped<Vec<u8>> {
384 type Error = std::io::Error;
385
386 async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
387 let limit = req.limits().get("bytes").unwrap_or(Limits::BYTES);
388 data.open(limit).into_bytes().await.or_error(Status::BadRequest)
389 }
390}
391
392impl_strict_from_data_from_capped!(Vec<u8>);
393
394#[crate::async_trait]
395impl<'r> FromData<'r> for Data<'r> {
396 type Error = std::convert::Infallible;
397
398 async fn from_data(_: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
399 Success(data)
400 }
401}
402
403#[crate::async_trait]
404impl<'r, T: FromData<'r> + 'r> FromData<'r> for Result<T, T::Error> {
405 type Error = std::convert::Infallible;
406
407 async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
408 match T::from_data(req, data).await {
409 Success(v) => Success(Ok(v)),
410 Error((_, e)) => Success(Err(e)),
411 Forward(d) => Forward(d),
412 }
413 }
414}
415
416#[crate::async_trait]
417impl<'r, T: FromData<'r>> FromData<'r> for Option<T> {
418 type Error = std::convert::Infallible;
419
420 async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
421 match T::from_data(req, data).await {
422 Success(v) => Success(Some(v)),
423 Error(..) | Forward(..) => Success(None),
424 }
425 }
426}