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}