rocket/data/
data.rs

1use crate::tokio::io::AsyncReadExt;
2use crate::data::data_stream::DataStream;
3use crate::data::{ByteUnit, StreamReader};
4
5/// The number of bytes to read into the "peek" buffer.
6pub const PEEK_BYTES: usize = 512;
7
8/// Type representing the body data of a request.
9///
10/// This type is the only means by which the body of a request can be retrieved.
11/// This type is not usually used directly. Instead, data guards (types that
12/// implement [`FromData`](crate::data::FromData)) are created indirectly via
13/// code generation by specifying the `data = "<var>"` route parameter as
14/// follows:
15///
16/// ```rust
17/// # #[macro_use] extern crate rocket;
18/// # type DataGuard = String;
19/// #[post("/submit", data = "<var>")]
20/// fn submit(var: DataGuard) { /* ... */ }
21/// # fn main() { }
22/// ```
23///
24/// Above, `DataGuard` can be any type that implements `FromData`. Note that
25/// `Data` itself implements `FromData`.
26///
27/// # Reading Data
28///
29/// Data may be read from a `Data` object by calling either the
30/// [`open()`](Data::open()) or [`peek()`](Data::peek()) methods.
31///
32/// The `open` method consumes the `Data` object and returns the raw data
33/// stream. The `Data` object is consumed for safety reasons: consuming the
34/// object ensures that holding a `Data` object means that all of the data is
35/// available for reading.
36///
37/// The `peek` method returns a slice containing at most 512 bytes of buffered
38/// body data. This enables partially or fully reading from a `Data` object
39/// without consuming the `Data` object.
40pub struct Data<'r> {
41    buffer: Vec<u8>,
42    is_complete: bool,
43    stream: StreamReader<'r>,
44}
45
46impl<'r> Data<'r> {
47    /// Create a `Data` from a recognized `stream`.
48    pub(crate) fn from<S: Into<StreamReader<'r>>>(stream: S) -> Data<'r> {
49        // TODO.async: This used to also set the read timeout to 5 seconds.
50        // Such a short read timeout is likely no longer necessary, but some
51        // kind of idle timeout should be implemented.
52
53        let stream = stream.into();
54        let buffer = Vec::with_capacity(PEEK_BYTES / 8);
55        Data { buffer, stream, is_complete: false }
56    }
57
58    /// This creates a `data` object from a local data source `data`.
59    #[inline]
60    pub(crate) fn local(data: Vec<u8>) -> Data<'r> {
61        Data {
62            buffer: data,
63            stream: StreamReader::empty(),
64            is_complete: true,
65        }
66    }
67
68    /// Returns the raw data stream, limited to `limit` bytes.
69    ///
70    /// The stream contains all of the data in the body of the request,
71    /// including that in the `peek` buffer. The method consumes the `Data`
72    /// instance. This ensures that a `Data` type _always_ represents _all_ of
73    /// the data in a request.
74    ///
75    /// # Example
76    ///
77    /// ```rust
78    /// use rocket::data::{Data, ToByteUnit};
79    ///
80    /// # const SIZE_LIMIT: u64 = 2 << 20; // 2MiB
81    /// fn handler(data: Data<'_>) {
82    ///     let stream = data.open(2.mebibytes());
83    /// }
84    /// ```
85    pub fn open(self, limit: ByteUnit) -> DataStream<'r> {
86        DataStream::new(self.buffer, self.stream, limit.into())
87    }
88
89    /// Retrieve at most `num` bytes from the `peek` buffer without consuming
90    /// `self`.
91    ///
92    /// The peek buffer contains at most 512 bytes of the body of the request.
93    /// The actual size of the returned buffer is the `min` of the request's
94    /// body, `num` and `512`. The [`peek_complete`](#method.peek_complete)
95    /// method can be used to determine if this buffer contains _all_ of the
96    /// data in the body of the request.
97    ///
98    /// # Examples
99    ///
100    /// In a data guard:
101    ///
102    /// ```rust
103    /// use rocket::request::{self, Request, FromRequest};
104    /// use rocket::data::{Data, FromData, Outcome};
105    /// use rocket::http::Status;
106    /// # struct MyType;
107    /// # type MyError = String;
108    ///
109    /// #[rocket::async_trait]
110    /// impl<'r> FromData<'r> for MyType {
111    ///     type Error = MyError;
112    ///
113    ///     async fn from_data(r: &'r Request<'_>, mut data: Data<'r>) -> Outcome<'r, Self> {
114    ///         if data.peek(2).await != b"hi" {
115    ///             return Outcome::Forward((data, Status::BadRequest))
116    ///         }
117    ///
118    ///         /* .. */
119    ///         # unimplemented!()
120    ///     }
121    /// }
122    /// ```
123    ///
124    /// In a fairing:
125    ///
126    /// ```
127    /// use rocket::{Rocket, Request, Data, Response};
128    /// use rocket::fairing::{Fairing, Info, Kind};
129    /// # struct MyType;
130    ///
131    /// #[rocket::async_trait]
132    /// impl Fairing for MyType {
133    ///     fn info(&self) -> Info {
134    ///         Info {
135    ///             name: "Data Peeker",
136    ///             kind: Kind::Request
137    ///         }
138    ///     }
139    ///
140    ///     async fn on_request(&self, req: &mut Request<'_>, data: &mut Data<'_>) {
141    ///         if data.peek(2).await == b"hi" {
142    ///             /* do something; body data starts with `"hi"` */
143    ///         }
144    ///
145    ///         /* .. */
146    ///         # unimplemented!()
147    ///     }
148    /// }
149    /// ```
150    pub async fn peek(&mut self, num: usize) -> &[u8] {
151        let num = std::cmp::min(PEEK_BYTES, num);
152        let mut len = self.buffer.len();
153        if len >= num {
154            return &self.buffer[..num];
155        }
156
157        while len < num {
158            match self.stream.read_buf(&mut self.buffer).await {
159                Ok(0) => { self.is_complete = true; break },
160                Ok(n) => len += n,
161                Err(e) => {
162                    error_!("Failed to read into peek buffer: {:?}.", e);
163                    break;
164                }
165            }
166        }
167
168        &self.buffer[..std::cmp::min(len, num)]
169    }
170
171    /// Returns true if the `peek` buffer contains all of the data in the body
172    /// of the request. Returns `false` if it does not or if it is not known if
173    /// it does.
174    ///
175    /// # Example
176    ///
177    /// ```rust
178    /// use rocket::data::Data;
179    ///
180    /// async fn handler(mut data: Data<'_>) {
181    ///     if data.peek_complete() {
182    ///         println!("All of the data: {:?}", data.peek(512).await);
183    ///     }
184    /// }
185    /// ```
186    #[inline(always)]
187    pub fn peek_complete(&self) -> bool {
188        self.is_complete
189    }
190}