rocket/data/
data.rs

1use std::io;
2use std::pin::Pin;
3
4use crate::data::ByteUnit;
5use crate::data::data_stream::{DataStream, RawReader, RawStream};
6use crate::data::peekable::Peekable;
7use crate::data::transform::{Transform, TransformBuf, Inspect, InPlaceMap};
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;
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 { stream, transforms: Vec::new() }
52    }
53
54    #[inline]
55    pub(crate) fn from<S: Into<RawStream<'r>>>(stream: S) -> Data<'r> {
56        Data::new(Peekable::new(RawReader::new(stream.into())))
57    }
58
59    /// This creates a `data` object from a local data source `data`.
60    #[inline]
61    pub(crate) fn local(data: Vec<u8>) -> Data<'r> {
62        Data::new(Peekable::with_buffer(data, true, RawReader::new(RawStream::Empty)))
63    }
64
65    /// Returns the raw data stream, limited to `limit` bytes.
66    ///
67    /// The stream contains all of the data in the body of the request,
68    /// including that in the `peek` buffer. The method consumes the `Data`
69    /// instance. This ensures that a `Data` type _always_ represents _all_ of
70    /// the data in a request.
71    ///
72    /// # Example
73    ///
74    /// ```rust
75    /// use rocket::data::{Data, ToByteUnit};
76    ///
77    /// # const SIZE_LIMIT: u64 = 2 << 20; // 2MiB
78    /// fn handler(data: Data<'_>) {
79    ///     let stream = data.open(2.mebibytes());
80    /// }
81    /// ```
82    #[inline(always)]
83    pub fn open(self, limit: ByteUnit) -> DataStream<'r> {
84        DataStream::new(self.transforms, self.stream, limit.into())
85    }
86
87    /// Fills the peek buffer with body data until it contains at least `num`
88    /// bytes (capped to 512), or the complete body data, whichever is less, and
89    /// returns it. If the buffer already contains either at least `num` bytes
90    /// or all of the body data, no I/O is performed and the buffer is simply
91    /// returned. If `num` is greater than `512`, it is artificially capped to
92    /// `512`.
93    ///
94    /// No guarantees are made about the actual size of the returned buffer
95    /// except that it will not exceed the length of the body data. It may be:
96    ///
97    ///   * Less than `num` if `num > 512` or the complete body data is `< 512`
98    ///     or an error occurred while reading the body.
99    ///   * Equal to `num` if `num` is `<= 512` and exactly `num` bytes of the
100    ///     body data were successfully read.
101    ///   * Greater than `num` if `> num` bytes of the body data have
102    ///     successfully been read, either by this request, a previous request,
103    ///     or opportunistically.
104    ///
105    /// [`Data::peek_complete()`] can be used to determine if this buffer
106    /// contains the complete body data.
107    ///
108    /// # Examples
109    ///
110    /// In a data guard:
111    ///
112    /// ```rust
113    /// use rocket::request::{self, Request, FromRequest};
114    /// use rocket::data::{Data, FromData, Outcome};
115    /// use rocket::http::Status;
116    /// # struct MyType;
117    /// # type MyError = String;
118    ///
119    /// #[rocket::async_trait]
120    /// impl<'r> FromData<'r> for MyType {
121    ///     type Error = MyError;
122    ///
123    ///     async fn from_data(r: &'r Request<'_>, mut data: Data<'r>) -> Outcome<'r, Self> {
124    ///         if data.peek(2).await != b"hi" {
125    ///             return Outcome::Forward((data, Status::BadRequest))
126    ///         }
127    ///
128    ///         /* .. */
129    ///         # unimplemented!()
130    ///     }
131    /// }
132    /// ```
133    ///
134    /// In a fairing:
135    ///
136    /// ```
137    /// use rocket::{Rocket, Request, Data, Response};
138    /// use rocket::fairing::{Fairing, Info, Kind};
139    /// # struct MyType;
140    ///
141    /// #[rocket::async_trait]
142    /// impl Fairing for MyType {
143    ///     fn info(&self) -> Info {
144    ///         Info {
145    ///             name: "Data Peeker",
146    ///             kind: Kind::Request
147    ///         }
148    ///     }
149    ///
150    ///     async fn on_request(&self, req: &mut Request<'_>, data: &mut Data<'_>) {
151    ///         if data.peek(2).await == b"hi" {
152    ///             /* do something; body data starts with `"hi"` */
153    ///         }
154    ///
155    ///         /* .. */
156    ///         # unimplemented!()
157    ///     }
158    /// }
159    /// ```
160    #[inline(always)]
161    pub async fn peek(&mut self, num: usize) -> &[u8] {
162        self.stream.peek(num).await
163    }
164
165    /// Returns true if the `peek` buffer contains all of the data in the body
166    /// of the request. Returns `false` if it does not or it is not known.
167    ///
168    /// # Example
169    ///
170    /// ```rust
171    /// use rocket::data::Data;
172    ///
173    /// async fn handler(mut data: Data<'_>) {
174    ///     if data.peek_complete() {
175    ///         println!("All of the data: {:?}", data.peek(512).await);
176    ///     }
177    /// }
178    /// ```
179    #[inline(always)]
180    pub fn peek_complete(&self) -> bool {
181        self.stream.complete
182    }
183
184    /// Chains the [`Transform`] `transform` to `self`.
185    ///
186    /// Note that transforms do nothing until the data is
187    /// [`open()`ed](Data::open()) and read.
188    #[inline(always)]
189    pub fn chain_transform<T>(&mut self, transform: T) -> &mut Self
190        where T: Transform + Send + Sync + 'static
191    {
192        self.transforms.push(Box::pin(transform));
193        self
194    }
195
196    /// Chain a [`Transform`] that can inspect the data as it streams.
197    pub fn chain_inspect<F>(&mut self, f: F) -> &mut Self
198        where F: FnMut(&[u8]) + Send + Sync + 'static
199    {
200        self.chain_transform(Inspect(Box::new(f)))
201    }
202
203    /// Chain a [`Transform`] that can in-place map the data as it streams.
204    /// Unlike [`Data::chain_try_inplace_map()`], this version assumes the
205    /// mapper is infallible.
206    pub fn chain_inplace_map<F>(&mut self, mut f: F) -> &mut Self
207        where F: FnMut(&mut TransformBuf<'_, '_>) + Send + Sync + 'static
208    {
209        self.chain_transform(InPlaceMap(Box::new(move |buf| Ok(f(buf)))))
210    }
211
212    /// Chain a [`Transform`] that can in-place map the data as it streams.
213    /// Unlike [`Data::chain_inplace_map()`], this version allows the mapper to
214    /// be infallible.
215    pub fn chain_try_inplace_map<F>(&mut self, f: F) -> &mut Self
216        where F: FnMut(&mut TransformBuf<'_, '_>) -> io::Result<()> + Send + Sync + 'static
217    {
218        self.chain_transform(InPlaceMap(Box::new(f)))
219    }
220}