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}}