rocket/local/
request.rs

1macro_rules! pub_request_impl {
2    ($import:literal $($prefix:tt $suffix:tt)?) =>
3{
4    /// Borrows the inner `Request` as seen by Rocket.
5    ///
6    /// Note that no routing has occurred and that there is no remote
7    /// address unless one has been explicitly set with
8    /// [`set_remote()`](Request::set_remote()).
9    ///
10    /// # Example
11    ///
12    /// ```rust
13    #[doc = $import]
14    ///
15    /// # Client::_test(|_, request, _| {
16    /// let request: LocalRequest = request;
17    /// let inner: &rocket::Request = request.inner();
18    /// # });
19    /// ```
20    #[inline(always)]
21    pub fn inner(&self) -> &Request<'c> {
22        self._request()
23    }
24
25    /// Mutably borrows the inner `Request` as seen by Rocket.
26    ///
27    /// Note that no routing has occurred and that there is no remote
28    /// address unless one has been explicitly set with
29    /// [`set_remote()`](Request::set_remote()).
30    ///
31    /// # Example
32    ///
33    /// ```rust
34    #[doc = $import]
35    ///
36    /// # Client::_test(|_, request, _| {
37    /// let mut request: LocalRequest = request;
38    /// let inner: &mut rocket::Request = request.inner_mut();
39    /// # });
40    /// ```
41    #[inline(always)]
42    pub fn inner_mut(&mut self) -> &mut Request<'c> {
43        self._request_mut()
44    }
45
46    /// Add a header to this request.
47    ///
48    /// Any type that implements `Into<Header>` can be used here. Among
49    /// others, this includes [`ContentType`] and [`Accept`].
50    ///
51    /// [`ContentType`]: crate::http::ContentType
52    /// [`Accept`]: crate::http::Accept
53    ///
54    /// # Examples
55    ///
56    /// Add the Content-Type header:
57    ///
58    /// ```rust
59    #[doc = $import]
60    /// use rocket::http::Header;
61    /// use rocket::http::ContentType;
62    ///
63    /// # Client::_test(|_, request, _| {
64    /// let request: LocalRequest = request;
65    /// let req = request
66    ///     .header(ContentType::JSON)
67    ///     .header(Header::new("X-Custom", "custom-value"));
68    /// # });
69    /// ```
70    #[inline]
71    pub fn header<H>(mut self, header: H) -> Self
72        where H: Into<crate::http::Header<'static>>
73    {
74        self._request_mut().add_header(header.into());
75        self
76    }
77
78    /// Adds a header to this request without consuming `self`.
79    ///
80    /// # Examples
81    ///
82    /// Add the Content-Type header:
83    ///
84    /// ```rust
85    #[doc = $import]
86    /// use rocket::http::ContentType;
87    ///
88    /// # Client::_test(|_, mut request, _| {
89    /// let mut request: LocalRequest = request;
90    /// request.add_header(ContentType::JSON);
91    /// # });
92    /// ```
93    #[inline]
94    pub fn add_header<H>(&mut self, header: H)
95        where H: Into<crate::http::Header<'static>>
96    {
97        self._request_mut().add_header(header.into());
98    }
99
100    /// Set the remote address of this request.
101    ///
102    /// # Examples
103    ///
104    /// Set the remote address to "8.8.8.8:80":
105    ///
106    /// ```rust
107    #[doc = $import]
108    ///
109    /// # Client::_test(|_, request, _| {
110    /// let request: LocalRequest = request;
111    /// let address = "8.8.8.8:80".parse().unwrap();
112    /// let req = request.remote(address);
113    /// # });
114    /// ```
115    #[inline]
116    pub fn remote(mut self, address: std::net::SocketAddr) -> Self {
117        self.set_remote(address);
118        self
119    }
120
121    /// Add a cookie to this request.
122    ///
123    /// # Examples
124    ///
125    /// Add `user_id` cookie:
126    ///
127    /// ```rust
128    #[doc = $import]
129    /// use rocket::http::Cookie;
130    ///
131    /// # Client::_test(|_, request, _| {
132    /// let request: LocalRequest = request;
133    /// let req = request
134    ///     .cookie(("username", "sb"))
135    ///     .cookie(("user_id", "12"));
136    /// # });
137    /// ```
138    #[inline]
139    pub fn cookie<'a, C>(mut self, cookie: C) -> Self
140        where C: Into<crate::http::Cookie<'a>>
141    {
142        self._request_mut().cookies_mut().add_original(cookie.into().into_owned());
143        self
144    }
145
146    /// Add all of the cookies in `cookies` to this request.
147    ///
148    /// # Example
149    ///
150    /// ```rust
151    #[doc = $import]
152    /// use rocket::http::Cookie;
153    ///
154    /// # Client::_test(|_, request, _| {
155    /// let request: LocalRequest = request;
156    /// let cookies = vec![("a", "b"), ("c", "d")];
157    /// let req = request.cookies(cookies);
158    /// # });
159    /// ```
160    #[inline]
161    pub fn cookies<'a, C, I>(mut self, cookies: I) -> Self
162        where C: Into<crate::http::Cookie<'a>>,
163              I: IntoIterator<Item = C>
164    {
165        for cookie in cookies {
166            let cookie: crate::http::Cookie<'_> = cookie.into();
167            self._request_mut().cookies_mut().add_original(cookie.into_owned());
168        }
169
170        self
171    }
172
173    /// Add a [private cookie] to this request.
174    ///
175    /// [private cookie]: crate::http::CookieJar::add_private()
176    ///
177    /// # Examples
178    ///
179    /// Add `user_id` as a private cookie:
180    ///
181    /// ```rust
182    #[doc = $import]
183    /// use rocket::http::Cookie;
184    ///
185    /// # Client::_test(|_, request, _| {
186    /// let request: LocalRequest = request;
187    /// let req = request.private_cookie(("user_id", "sb"));
188    /// # });
189    /// ```
190    #[cfg(feature = "secrets")]
191    #[cfg_attr(nightly, doc(cfg(feature = "secrets")))]
192    #[inline]
193    pub fn private_cookie<C>(mut self, cookie: C) -> Self
194        where C: Into<crate::http::Cookie<'static>>
195    {
196        self._request_mut().cookies_mut().add_original_private(cookie.into());
197        self
198    }
199
200    /// Set mTLS client certificates to send along with the request.
201    ///
202    /// If the request already contained certificates, they are replaced with
203    /// those in `reader.`
204    ///
205    /// `reader` is expected to be PEM-formatted and contain X509 certificates.
206    /// If it contains more than one certificate, the entire chain is set on the
207    /// request. If it contains items other than certificates, the certificate
208    /// chain up to the first non-certificate item is set on the request. If
209    /// `reader` is syntactically invalid PEM, certificates are cleared on the
210    /// request.
211    ///
212    /// The type `C` can be anything that implements [`std::io::Read`]. This
213    /// includes: `&[u8]`, `File`, `&File`, `Stdin`, and so on. To read a file
214    /// in at compile-time, use [`include_bytes!()`].
215    ///
216    /// ```rust
217    /// use std::fs::File;
218    ///
219    #[doc = $import]
220    /// use rocket::fs::relative;
221    ///
222    /// # Client::_test(|_, request, _| {
223    /// let request: LocalRequest = request;
224    /// let path = relative!("../../examples/tls/private/ed25519_cert.pem");
225    /// let req = request.identity(File::open(path).unwrap());
226    /// # });
227    /// ```
228    #[cfg(feature = "mtls")]
229    #[cfg_attr(nightly, doc(cfg(feature = "mtls")))]
230    pub fn identity<C: std::io::Read>(mut self, reader: C) -> Self {
231        use crate::http::{tls::util::load_certs, private::Certificates};
232
233        let mut reader = std::io::BufReader::new(reader);
234        let certs = load_certs(&mut reader).map(Certificates::from);
235        self._request_mut().connection.client_certificates = certs.ok();
236        self
237    }
238
239    /// Sets the body data of the request.
240    ///core/lib/src/local/request.rs
241    /// # Examples
242    ///
243    /// ```rust
244    #[doc = $import]
245    /// use rocket::http::ContentType;
246    ///
247    /// # Client::_test(|_, request, _| {
248    /// let request: LocalRequest = request;
249    /// let req = request
250    ///     .header(ContentType::Text)
251    ///     .body("Hello, world!");
252    /// # });
253    /// ```
254    #[inline]
255    pub fn body<S: AsRef<[u8]>>(mut self, body: S) -> Self {
256        // TODO: For CGI, we want to be able to set the body to be stdin
257        // without actually reading everything into a vector. Can we allow
258        // that here while keeping the simplicity? Looks like it would
259        // require us to reintroduce a NetStream::Local(Box<Read>) or
260        // something like that.
261        *self._body_mut() = body.as_ref().into();
262        self
263    }
264
265    /// Sets the body to `value` serialized as JSON with `Content-Type`
266    /// [`ContentType::JSON`](crate::http::ContentType::JSON).
267    ///
268    /// If `value` fails to serialize, the body is set to empty. The
269    /// `Content-Type` header is _always_ set.
270    ///
271    /// # Examples
272    ///
273    /// ```rust
274    #[doc = $import]
275    /// use rocket::serde::Serialize;
276    /// use rocket::http::ContentType;
277    ///
278    /// #[derive(Serialize)]
279    /// struct Task {
280    ///     id: usize,
281    ///     complete: bool,
282    /// }
283    ///
284    /// # Client::_test(|_, request, _| {
285    /// let task = Task { id: 10, complete: false };
286    ///
287    /// let request: LocalRequest = request;
288    /// let req = request.json(&task);
289    /// assert_eq!(req.content_type(), Some(&ContentType::JSON));
290    /// # });
291    /// ```
292    #[cfg(feature = "json")]
293    #[cfg_attr(nightly, doc(cfg(feature = "json")))]
294    pub fn json<T: crate::serde::Serialize>(self, value: &T) -> Self {
295        let json = serde_json::to_vec(&value).unwrap_or_default();
296        self.header(crate::http::ContentType::JSON).body(json)
297    }
298
299    /// Sets the body to `value` serialized as MessagePack with `Content-Type`
300    /// [`ContentType::MsgPack`](crate::http::ContentType::MsgPack).
301    ///
302    /// If `value` fails to serialize, the body is set to empty. The
303    /// `Content-Type` header is _always_ set.
304    ///
305    /// # Examples
306    ///
307    /// ```rust
308    #[doc = $import]
309    /// use rocket::serde::Serialize;
310    /// use rocket::http::ContentType;
311    ///
312    /// #[derive(Serialize)]
313    /// struct Task {
314    ///     id: usize,
315    ///     complete: bool,
316    /// }
317    ///
318    /// # Client::_test(|_, request, _| {
319    /// let task = Task { id: 10, complete: false };
320    ///
321    /// let request: LocalRequest = request;
322    /// let req = request.msgpack(&task);
323    /// assert_eq!(req.content_type(), Some(&ContentType::MsgPack));
324    /// # });
325    /// ```
326    #[cfg(feature = "msgpack")]
327    #[cfg_attr(nightly, doc(cfg(feature = "msgpack")))]
328    pub fn msgpack<T: crate::serde::Serialize>(self, value: &T) -> Self {
329        let msgpack = rmp_serde::to_vec(value).unwrap_or_default();
330        self.header(crate::http::ContentType::MsgPack).body(msgpack)
331    }
332
333    /// Set the body (data) of the request without consuming `self`.
334    ///
335    /// # Examples
336    ///
337    /// Set the body to be a JSON structure; also sets the Content-Type.
338    ///
339    /// ```rust
340    #[doc = $import]
341    /// use rocket::http::ContentType;
342    ///
343    /// # Client::_test(|_, request, _| {
344    /// let request: LocalRequest = request;
345    /// let mut request = request.header(ContentType::JSON);
346    /// request.set_body(r#"{ "key": "value", "array": [1, 2, 3] }"#);
347    /// # });
348    /// ```
349    #[inline]
350    pub fn set_body<S: AsRef<[u8]>>(&mut self, body: S) {
351        *self._body_mut() = body.as_ref().into();
352    }
353
354    /// Dispatches the request, returning the response.
355    ///
356    /// This method consumes `self` and is the preferred mechanism for
357    /// dispatching.
358    ///
359    /// # Example
360    ///
361    /// ```rust
362    #[doc = $import]
363    ///
364    /// # Client::_test(|_, request, _| {
365    /// let request: LocalRequest = request;
366    /// let response = request.dispatch();
367    /// # });
368    /// ```
369    #[inline(always)]
370    pub $($prefix)? fn dispatch(self) -> LocalResponse<'c> {
371        self._dispatch()$(.$suffix)?
372    }
373
374    #[cfg(test)]
375    #[allow(dead_code)]
376    fn _ensure_impls_exist() {
377        fn is_clone_debug<T: Clone + std::fmt::Debug>() {}
378        is_clone_debug::<Self>();
379
380        fn is_deref_req<'a, T: std::ops::Deref<Target = Request<'a>>>() {}
381        is_deref_req::<Self>();
382
383        fn is_deref_mut_req<'a, T: std::ops::DerefMut<Target = Request<'a>>>() {}
384        is_deref_mut_req::<Self>();
385    }
386}}