rocket_community/data/
data.rs

1use std::io;
2use std::pin::Pin;
3
4use crate::data::data_stream::{DataStream, RawReader, RawStream};
5use crate::data::peekable::Peekable;
6use crate::data::transform::{InPlaceMap, Inspect, Transform, TransformBuf};
7use crate::data::ByteUnit;
8
9/// Type representing the body data of a request.
10///
11/// This type is the only means by which the body of a request can be retrieved.
12/// This type is not usually used directly. Instead, data guards (types that
13/// implement [`FromData`](crate::data::FromData)) are created indirectly via
14/// code generation by specifying the `data = "<var>"` route parameter as
15/// follows:
16///
17/// ```rust
18/// # #[macro_use] extern crate rocket_community as rocket;
19/// # type DataGuard = String;
20/// #[post("/submit", data = "<var>")]
21/// fn submit(var: DataGuard) { /* ... */ }
22/// # fn main() { }
23/// ```
24///
25/// Above, `DataGuard` can be any type that implements `FromData`. Note that
26/// `Data` itself implements `FromData`.
27///
28/// # Reading Data
29///
30/// Data may be read from a `Data` object by calling either the
31/// [`open()`](Data::open()) or [`peek()`](Data::peek()) methods.
32///
33/// The `open` method consumes the `Data` object and returns the raw data
34/// stream. The `Data` object is consumed for safety reasons: consuming the
35/// object ensures that holding a `Data` object means that all of the data is
36/// available for reading.
37///
38/// The `peek` method returns a slice containing at most 512 bytes of buffered
39/// body data. This enables partially or fully reading from a `Data` object
40/// without consuming the `Data` object.
41pub struct Data<'r> {
42    stream: Peekable<512, RawReader<'r>>,
43    transforms: Vec<Pin<Box<dyn Transform + Send + Sync + 'r>>>,
44}
45
46// TODO: Before `async`, we had a read timeout of 5s. Such a short read timeout
47// is likely no longer necessary, but an idle timeout should be implemented.
48impl<'r> Data<'r> {
49    #[inline]
50    pub(crate) fn new(stream: Peekable<512, RawReader<'r>>) -> Self {
51        Self {
52            stream,
53            transforms: Vec::new(),
54        }
55    }
56
57    #[inline]
58    pub(crate) fn from<S: Into<RawStream<'r>>>(stream: S) -> Data<'r> {
59        Data::new(Peekable::new(RawReader::new(stream.into())))
60    }
61
62    /// This creates a `data` object from a local data source `data`.
63    #[inline]
64    pub(crate) fn local(data: Vec<u8>) -> Data<'r> {
65        Data::new(Peekable::with_buffer(
66            data,
67            true,
68            RawReader::new(RawStream::Empty),
69        ))
70    }
71
72    /// Returns the raw data stream, limited to `limit` bytes.
73    ///
74    /// The stream contains all of the data in the body of the request,
75    /// including that in the `peek` buffer. The method consumes the `Data`
76    /// instance. This ensures that a `Data` type _always_ represents _all_ of
77    /// the data in a request.
78    ///
79    /// # Example
80    ///
81    /// ```rust
82    /// # extern crate rocket_community as rocket;
83    /// use rocket::data::{Data, ToByteUnit};
84    ///
85    /// # const SIZE_LIMIT: u64 = 2 << 20; // 2MiB
86    /// fn handler(data: Data<'_>) {
87    ///     let stream = data.open(2.mebibytes());
88    /// }
89    /// ```
90    #[inline(always)]
91    pub fn open(self, limit: ByteUnit) -> DataStream<'r> {
92        DataStream::new(self.transforms, self.stream, limit.into())
93    }
94
95    /// Fills the peek buffer with body data until it contains at least `num`
96    /// bytes (capped to 512), or the complete body data, whichever is less, and
97    /// returns it. If the buffer already contains either at least `num` bytes
98    /// or all of the body data, no I/O is performed and the buffer is simply
99    /// returned. If `num` is greater than `512`, it is artificially capped to
100    /// `512`.
101    ///
102    /// No guarantees are made about the actual size of the returned buffer
103    /// except that it will not exceed the length of the body data. It may be:
104    ///
105    ///   * Less than `num` if `num > 512` or the complete body data is `< 512`
106    ///     or an error occurred while reading the body.
107    ///   * Equal to `num` if `num` is `<= 512` and exactly `num` bytes of the
108    ///     body data were successfully read.
109    ///   * Greater than `num` if `> num` bytes of the body data have
110    ///     successfully been read, either by this request, a previous request,
111    ///     or opportunistically.
112    ///
113    /// [`Data::peek_complete()`] can be used to determine if this buffer
114    /// contains the complete body data.
115    ///
116    /// # Examples
117    ///
118    /// In a data guard:
119    ///
120    /// ```rust
121    /// # extern crate rocket_community as rocket;
122    /// use rocket::request::{self, Request, FromRequest};
123    /// use rocket::data::{Data, FromData, Outcome};
124    /// use rocket::http::Status;
125    /// # struct MyType;
126    /// # type MyError = String;
127    ///
128    /// #[rocket::async_trait]
129    /// impl<'r> FromData<'r> for MyType {
130    ///     type Error = MyError;
131    ///
132    ///     async fn from_data(r: &'r Request<'_>, mut data: Data<'r>) -> Outcome<'r, Self> {
133    ///         if data.peek(2).await != b"hi" {
134    ///             return Outcome::Forward((data, Status::BadRequest))
135    ///         }
136    ///
137    ///         /* .. */
138    ///         # unimplemented!()
139    ///     }
140    /// }
141    /// ```
142    ///
143    /// In a fairing:
144    ///
145    /// ```rust
146    /// # extern crate rocket_community as rocket;
147    /// use rocket::{Rocket, Request, Data, Response};
148    /// use rocket::fairing::{Fairing, Info, Kind};
149    /// # struct MyType;
150    ///
151    /// #[rocket::async_trait]
152    /// impl Fairing for MyType {
153    ///     fn info(&self) -> Info {
154    ///         Info {
155    ///             name: "Data Peeker",
156    ///             kind: Kind::Request
157    ///         }
158    ///     }
159    ///
160    ///     async fn on_request(&self, req: &mut Request<'_>, data: &mut Data<'_>) {
161    ///         if data.peek(2).await == b"hi" {
162    ///             /* do something; body data starts with `"hi"` */
163    ///         }
164    ///
165    ///         /* .. */
166    ///         # unimplemented!()
167    ///     }
168    /// }
169    /// ```
170    #[inline(always)]
171    pub async fn peek(&mut self, num: usize) -> &[u8] {
172        self.stream.peek(num).await
173    }
174
175    /// Returns true if the `peek` buffer contains all of the data in the body
176    /// of the request. Returns `false` if it does not or it is not known.
177    ///
178    /// # Example
179    ///
180    /// ```rust
181    /// # extern crate rocket_community as rocket;
182    /// use rocket::data::Data;
183    ///
184    /// async fn handler(mut data: Data<'_>) {
185    ///     if data.peek_complete() {
186    ///         println!("All of the data: {:?}", data.peek(512).await);
187    ///     }
188    /// }
189    /// ```
190    #[inline(always)]
191    pub fn peek_complete(&self) -> bool {
192        self.stream.complete
193    }
194
195    /// Chains the [`Transform`] `transform` to `self`.
196    ///
197    /// Note that transforms do nothing until the data is
198    /// [`open()`ed](Data::open()) and read.
199    #[inline(always)]
200    pub fn chain_transform<T>(&mut self, transform: T) -> &mut Self
201    where
202        T: Transform + Send + Sync + 'static,
203    {
204        self.transforms.push(Box::pin(transform));
205        self
206    }
207
208    /// Chain a [`Transform`] that can inspect the data as it streams.
209    pub fn chain_inspect<F>(&mut self, f: F) -> &mut Self
210    where
211        F: FnMut(&[u8]) + Send + Sync + 'static,
212    {
213        self.chain_transform(Inspect(Box::new(f)))
214    }
215
216    /// Chain a [`Transform`] that can in-place map the data as it streams.
217    /// Unlike [`Data::chain_try_inplace_map()`], this version assumes the
218    /// mapper is infallible.
219    pub fn chain_inplace_map<F>(&mut self, mut f: F) -> &mut Self
220    where
221        F: FnMut(&mut TransformBuf<'_, '_>) + Send + Sync + 'static,
222    {
223        self.chain_transform(InPlaceMap(Box::new(move |buf| {
224            f(buf);
225            Ok(())
226        })))
227    }
228
229    /// Chain a [`Transform`] that can in-place map the data as it streams.
230    /// Unlike [`Data::chain_inplace_map()`], this version allows the mapper to
231    /// be infallible.
232    pub fn chain_try_inplace_map<F>(&mut self, f: F) -> &mut Self
233    where
234        F: FnMut(&mut TransformBuf<'_, '_>) -> io::Result<()> + Send + Sync + 'static,
235    {
236        self.chain_transform(InPlaceMap(Box::new(f)))
237    }
238}