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}