rocket/request/request.rs
1use std::fmt;
2use std::ops::RangeFrom;
3use std::{future::Future, borrow::Cow, sync::Arc};
4use std::net::{IpAddr, SocketAddr};
5
6use yansi::Paint;
7use state::{TypeMap, InitCell};
8use futures::future::BoxFuture;
9use atomic::{Atomic, Ordering};
10
11use crate::{Rocket, Route, Orbit};
12use crate::request::{FromParam, FromSegments, FromRequest, Outcome};
13use crate::form::{self, ValueField, FromForm};
14use crate::data::Limits;
15
16use crate::http::{hyper, Method, Header, HeaderMap};
17use crate::http::{ContentType, Accept, MediaType, CookieJar, Cookie};
18use crate::http::uncased::UncasedStr;
19use crate::http::private::Certificates;
20use crate::http::uri::{fmt::Path, Origin, Segments, Host, Authority};
21
22/// The type of an incoming web request.
23///
24/// This should be used sparingly in Rocket applications. In particular, it
25/// should likely only be used when writing [`FromRequest`] implementations. It
26/// contains all of the information for a given web request except for the body
27/// data. This includes the HTTP method, URI, cookies, headers, and more.
28pub struct Request<'r> {
29 method: Atomic<Method>,
30 uri: Origin<'r>,
31 headers: HeaderMap<'r>,
32 pub(crate) connection: ConnectionMeta,
33 pub(crate) state: RequestState<'r>,
34}
35
36/// Information derived from an incoming connection, if any.
37#[derive(Clone)]
38pub(crate) struct ConnectionMeta {
39 pub remote: Option<SocketAddr>,
40 #[cfg_attr(not(feature = "mtls"), allow(dead_code))]
41 pub client_certificates: Option<Certificates>,
42}
43
44/// Information derived from the request.
45pub(crate) struct RequestState<'r> {
46 pub rocket: &'r Rocket<Orbit>,
47 pub route: Atomic<Option<&'r Route>>,
48 pub cookies: CookieJar<'r>,
49 pub accept: InitCell<Option<Accept>>,
50 pub content_type: InitCell<Option<ContentType>>,
51 pub cache: Arc<TypeMap![Send + Sync]>,
52 pub host: Option<Host<'r>>,
53}
54
55impl Request<'_> {
56 pub(crate) fn clone(&self) -> Self {
57 Request {
58 method: Atomic::new(self.method()),
59 uri: self.uri.clone(),
60 headers: self.headers.clone(),
61 connection: self.connection.clone(),
62 state: self.state.clone(),
63 }
64 }
65}
66
67impl RequestState<'_> {
68 fn clone(&self) -> Self {
69 RequestState {
70 rocket: self.rocket,
71 route: Atomic::new(self.route.load(Ordering::Acquire)),
72 cookies: self.cookies.clone(),
73 accept: self.accept.clone(),
74 content_type: self.content_type.clone(),
75 cache: self.cache.clone(),
76 host: self.host.clone(),
77 }
78 }
79}
80
81impl<'r> Request<'r> {
82 /// Create a new `Request` with the given `method` and `uri`.
83 #[inline(always)]
84 pub(crate) fn new<'s: 'r>(
85 rocket: &'r Rocket<Orbit>,
86 method: Method,
87 uri: Origin<'s>
88 ) -> Request<'r> {
89 Request {
90 uri,
91 method: Atomic::new(method),
92 headers: HeaderMap::new(),
93 connection: ConnectionMeta {
94 remote: None,
95 client_certificates: None,
96 },
97 state: RequestState {
98 rocket,
99 route: Atomic::new(None),
100 cookies: CookieJar::new(rocket.config()),
101 accept: InitCell::new(),
102 content_type: InitCell::new(),
103 cache: Arc::new(<TypeMap![Send + Sync]>::new()),
104 host: None,
105 }
106 }
107 }
108
109 /// Retrieve the method from `self`.
110 ///
111 /// # Example
112 ///
113 /// ```rust
114 /// use rocket::http::Method;
115 ///
116 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
117 /// # let get = |uri| c.get(uri);
118 /// # let post = |uri| c.post(uri);
119 /// assert_eq!(get("/").method(), Method::Get);
120 /// assert_eq!(post("/").method(), Method::Post);
121 /// ```
122 #[inline(always)]
123 pub fn method(&self) -> Method {
124 self.method.load(Ordering::Acquire)
125 }
126
127 /// Set the method of `self` to `method`.
128 ///
129 /// # Example
130 ///
131 /// ```rust
132 /// use rocket::http::Method;
133 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
134 /// # let mut req = c.get("/");
135 /// # let request = req.inner_mut();
136 ///
137 /// assert_eq!(request.method(), Method::Get);
138 ///
139 /// request.set_method(Method::Post);
140 /// assert_eq!(request.method(), Method::Post);
141 /// ```
142 #[inline(always)]
143 pub fn set_method(&mut self, method: Method) {
144 self._set_method(method);
145 }
146
147 /// Borrow the [`Origin`] URI from `self`.
148 ///
149 /// # Example
150 ///
151 /// ```rust
152 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
153 /// # let get = |uri| c.get(uri);
154 /// assert_eq!(get("/hello/rocketeer").uri().path(), "/hello/rocketeer");
155 /// assert_eq!(get("/hello").uri().query(), None);
156 /// ```
157 #[inline(always)]
158 pub fn uri(&self) -> &Origin<'r> {
159 &self.uri
160 }
161
162 /// Set the URI in `self` to `uri`.
163 ///
164 /// # Example
165 ///
166 /// ```rust
167 /// use rocket::http::uri::Origin;
168 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
169 /// # let mut req = c.get("/");
170 /// # let request = req.inner_mut();
171 ///
172 /// let uri = Origin::parse("/hello/Sergio?type=greeting").unwrap();
173 /// request.set_uri(uri);
174 /// assert_eq!(request.uri().path(), "/hello/Sergio");
175 /// assert_eq!(request.uri().query().unwrap(), "type=greeting");
176 ///
177 /// let new_uri = request.uri().map_path(|p| format!("/foo{}", p)).unwrap();
178 /// request.set_uri(new_uri);
179 /// assert_eq!(request.uri().path(), "/foo/hello/Sergio");
180 /// assert_eq!(request.uri().query().unwrap(), "type=greeting");
181 /// ```
182 #[inline(always)]
183 pub fn set_uri(&mut self, uri: Origin<'r>) {
184 self.uri = uri;
185 }
186
187 /// Returns the [`Host`] identified in the request, if any.
188 ///
189 /// If the request is made via HTTP/1.1 (or earlier), this method returns
190 /// the value in the `HOST` header without the deprecated `user_info`
191 /// component. Otherwise, this method returns the contents of the
192 /// `:authority` pseudo-header request field.
193 ///
194 /// Note that this method _only_ reflects the `HOST` header in the _initial_
195 /// request and not any changes made thereafter. To change the value
196 /// returned by this method, use [`Request::set_host()`].
197 ///
198 /// # ⚠️ DANGER ⚠️
199 ///
200 /// Using the user-controlled `host` to construct URLs is a security hazard!
201 /// _Never_ do so without first validating the host against a whitelist. For
202 /// this reason, Rocket disallows constructing host-prefixed URIs with
203 /// [`uri!`]. _Always_ use [`uri!`] to construct URIs.
204 ///
205 /// [`uri!`]: crate::uri!
206 ///
207 /// # Example
208 ///
209 /// Retrieve the raw host, unusable to construct safe URIs:
210 ///
211 /// ```rust
212 /// use rocket::http::uri::Host;
213 /// # use rocket::uri;
214 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
215 /// # let mut req = c.get("/");
216 /// # let request = req.inner_mut();
217 ///
218 /// assert_eq!(request.host(), None);
219 ///
220 /// request.set_host(Host::from(uri!("rocket.rs")));
221 /// let host = request.host().unwrap();
222 /// assert_eq!(host.domain(), "rocket.rs");
223 /// assert_eq!(host.port(), None);
224 ///
225 /// request.set_host(Host::from(uri!("rocket.rs:2392")));
226 /// let host = request.host().unwrap();
227 /// assert_eq!(host.domain(), "rocket.rs");
228 /// assert_eq!(host.port(), Some(2392));
229 /// ```
230 ///
231 /// Retrieve the raw host, check it against a whitelist, and construct a
232 /// URI:
233 ///
234 /// ```rust
235 /// # #[macro_use] extern crate rocket;
236 /// # type Token = String;
237 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
238 /// # let mut req = c.get("/");
239 /// # let request = req.inner_mut();
240 /// use rocket::http::uri::Host;
241 ///
242 /// // A sensitive URI we want to prefix with safe hosts.
243 /// #[get("/token?<secret>")]
244 /// fn token(secret: Token) { /* .. */ }
245 ///
246 /// // Whitelist of known hosts. In a real setting, you might retrieve this
247 /// // list from config at ignite-time using tools like `AdHoc::config()`.
248 /// const WHITELIST: [Host<'static>; 3] = [
249 /// Host::new(uri!("rocket.rs")),
250 /// Host::new(uri!("rocket.rs:443")),
251 /// Host::new(uri!("guide.rocket.rs:443")),
252 /// ];
253 ///
254 /// // A request with a host of "rocket.rs". Note the case-insensitivity.
255 /// request.set_host(Host::from(uri!("ROCKET.rs")));
256 /// let prefix = request.host().and_then(|h| h.to_absolute("https", &WHITELIST));
257 ///
258 /// // `rocket.rs` is in the whitelist, so we'll get back a `Some`.
259 /// assert!(prefix.is_some());
260 /// if let Some(prefix) = prefix {
261 /// // We can use this prefix to safely construct URIs.
262 /// let uri = uri!(prefix, token("some-secret-token"));
263 /// assert_eq!(uri, "https://ROCKET.rs/token?secret=some-secret-token");
264 /// }
265 ///
266 /// // A request with a host of "attacker-controlled.com".
267 /// request.set_host(Host::from(uri!("attacker-controlled.com")));
268 /// let prefix = request.host().and_then(|h| h.to_absolute("https", &WHITELIST));
269 ///
270 /// // `attacker-controlled.come` is _not_ on the whitelist.
271 /// assert!(prefix.is_none());
272 /// assert!(request.host().is_some());
273 /// ```
274 #[inline(always)]
275 pub fn host(&self) -> Option<&Host<'r>> {
276 self.state.host.as_ref()
277 }
278
279 /// Sets the host of `self` to `host`.
280 ///
281 /// # Example
282 ///
283 /// Set the host to `rocket.rs:443`.
284 ///
285 /// ```rust
286 /// use rocket::http::uri::Host;
287 /// # use rocket::uri;
288 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
289 /// # let mut req = c.get("/");
290 /// # let request = req.inner_mut();
291 ///
292 /// assert_eq!(request.host(), None);
293 ///
294 /// request.set_host(Host::from(uri!("rocket.rs:443")));
295 /// let host = request.host().unwrap();
296 /// assert_eq!(host.domain(), "rocket.rs");
297 /// assert_eq!(host.port(), Some(443));
298 /// ```
299 #[inline(always)]
300 pub fn set_host(&mut self, host: Host<'r>) {
301 self.state.host = Some(host);
302 }
303
304 /// Returns the raw address of the remote connection that initiated this
305 /// request if the address is known. If the address is not known, `None` is
306 /// returned.
307 ///
308 /// Because it is common for proxies to forward connections for clients, the
309 /// remote address may contain information about the proxy instead of the
310 /// client. For this reason, proxies typically set a "X-Real-IP" header
311 /// [`ip_header`](crate::Config::ip_header) with the client's true IP. To
312 /// extract this IP from the request, use the [`real_ip()`] or
313 /// [`client_ip()`] methods.
314 ///
315 /// [`real_ip()`]: #method.real_ip
316 /// [`client_ip()`]: #method.client_ip
317 ///
318 /// # Example
319 ///
320 /// ```rust
321 /// use std::net::{SocketAddrV4, Ipv4Addr};
322 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
323 /// # let mut req = c.get("/");
324 /// # let request = req.inner_mut();
325 ///
326 /// assert_eq!(request.remote(), None);
327 ///
328 /// let localhost = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 8000).into();
329 /// request.set_remote(localhost);
330 /// assert_eq!(request.remote(), Some(localhost));
331 /// ```
332 #[inline(always)]
333 pub fn remote(&self) -> Option<SocketAddr> {
334 self.connection.remote
335 }
336
337 /// Sets the remote address of `self` to `address`.
338 ///
339 /// # Example
340 ///
341 /// Set the remote address to be 127.0.0.1:8000:
342 ///
343 /// ```rust
344 /// use std::net::{SocketAddrV4, Ipv4Addr};
345 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
346 /// # let mut req = c.get("/");
347 /// # let request = req.inner_mut();
348 ///
349 /// assert_eq!(request.remote(), None);
350 ///
351 /// let localhost = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 8000).into();
352 /// request.set_remote(localhost);
353 /// assert_eq!(request.remote(), Some(localhost));
354 /// ```
355 #[inline(always)]
356 pub fn set_remote(&mut self, address: SocketAddr) {
357 self.connection.remote = Some(address);
358 }
359
360 /// Returns the IP address of the configured
361 /// [`ip_header`](crate::Config::ip_header) of the request if such a header
362 /// is configured, exists and contains a valid IP address.
363 ///
364 /// # Example
365 ///
366 /// ```rust
367 /// use std::net::Ipv4Addr;
368 /// use rocket::http::Header;
369 ///
370 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
371 /// # let req = c.get("/");
372 /// assert_eq!(req.real_ip(), None);
373 ///
374 /// // `ip_header` defaults to `X-Real-IP`.
375 /// let req = req.header(Header::new("X-Real-IP", "127.0.0.1"));
376 /// assert_eq!(req.real_ip(), Some(Ipv4Addr::LOCALHOST.into()));
377 /// ```
378 pub fn real_ip(&self) -> Option<IpAddr> {
379 let ip_header = self.rocket().config.ip_header.as_ref()?.as_str();
380 self.headers()
381 .get_one(ip_header)
382 .and_then(|ip| {
383 ip.parse()
384 .map_err(|_| warn_!("'{}' header is malformed: {}", ip_header, ip))
385 .ok()
386 })
387 }
388
389 /// Attempts to return the client's IP address by first inspecting the
390 /// [`ip_header`](crate::Config::ip_header) and then using the remote
391 /// connection's IP address. Note that the built-in `IpAddr` request guard
392 /// can be used to retrieve the same information in a handler:
393 ///
394 /// ```rust
395 /// # use rocket::get;
396 /// use std::net::IpAddr;
397 ///
398 /// #[get("/")]
399 /// fn get_ip(client_ip: IpAddr) { /* ... */ }
400 ///
401 /// #[get("/")]
402 /// fn try_get_ip(client_ip: Option<IpAddr>) { /* ... */ }
403 /// ````
404 ///
405 /// If the `ip_header` exists and contains a valid IP address, that address
406 /// is returned. Otherwise, if the address of the remote connection is
407 /// known, that address is returned. Otherwise, `None` is returned.
408 ///
409 /// # Example
410 ///
411 /// ```rust
412 /// # use rocket::http::Header;
413 /// # use std::net::{SocketAddr, IpAddr, Ipv4Addr};
414 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
415 /// # let mut req = c.get("/");
416 /// # let request = req.inner_mut();
417 ///
418 /// // starting without an "X-Real-IP" header or remote address
419 /// assert!(request.client_ip().is_none());
420 ///
421 /// // add a remote address; this is done by Rocket automatically
422 /// request.set_remote("127.0.0.1:8000".parse().unwrap());
423 /// assert_eq!(request.client_ip(), Some("127.0.0.1".parse().unwrap()));
424 ///
425 /// // now with an X-Real-IP header, the default value for `ip_header`.
426 /// request.add_header(Header::new("X-Real-IP", "8.8.8.8"));
427 /// assert_eq!(request.client_ip(), Some("8.8.8.8".parse().unwrap()));
428 /// ```
429 #[inline]
430 pub fn client_ip(&self) -> Option<IpAddr> {
431 self.real_ip().or_else(|| self.remote().map(|r| r.ip()))
432 }
433
434 /// Returns a wrapped borrow to the cookies in `self`.
435 ///
436 /// [`CookieJar`] implements internal mutability, so this method allows you
437 /// to get _and_ add/remove cookies in `self`.
438 ///
439 /// # Example
440 ///
441 /// Add a new cookie to a request's cookies:
442 ///
443 /// ```rust
444 /// use rocket::http::Cookie;
445 ///
446 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
447 /// # let request = c.get("/");
448 /// # let req = request.inner();
449 /// req.cookies().add(("key", "val"));
450 /// req.cookies().add(("ans", format!("life: {}", 38 + 4)));
451 ///
452 /// assert_eq!(req.cookies().get_pending("key").unwrap().value(), "val");
453 /// assert_eq!(req.cookies().get_pending("ans").unwrap().value(), "life: 42");
454 /// ```
455 #[inline(always)]
456 pub fn cookies(&self) -> &CookieJar<'r> {
457 &self.state.cookies
458 }
459
460 /// Returns a [`HeaderMap`] of all of the headers in `self`.
461 ///
462 /// # Example
463 ///
464 /// ```rust
465 /// use rocket::http::{Accept, ContentType};
466 ///
467 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
468 /// # let get = |uri| c.get(uri);
469 /// assert!(get("/").headers().is_empty());
470 ///
471 /// let req = get("/").header(Accept::HTML).header(ContentType::HTML);
472 /// assert_eq!(req.headers().len(), 2);
473 /// ```
474 #[inline(always)]
475 pub fn headers(&self) -> &HeaderMap<'r> {
476 &self.headers
477 }
478
479 /// Add `header` to `self`'s headers. The type of `header` can be any type
480 /// that implements the `Into<Header>` trait. This includes common types
481 /// such as [`ContentType`] and [`Accept`].
482 ///
483 /// # Example
484 ///
485 /// ```rust
486 /// use rocket::http::ContentType;
487 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
488 /// # let mut req = c.get("/");
489 /// # let request = req.inner_mut();
490 ///
491 /// assert!(request.headers().is_empty());
492 ///
493 /// request.add_header(ContentType::HTML);
494 /// assert!(request.headers().contains("Content-Type"));
495 /// assert_eq!(request.headers().len(), 1);
496 /// ```
497 #[inline]
498 pub fn add_header<'h: 'r, H: Into<Header<'h>>>(&mut self, header: H) {
499 let header = header.into();
500 self.bust_header_cache(header.name(), false);
501 self.headers.add(header);
502 }
503
504 /// Replaces the value of the header with name `header.name` with
505 /// `header.value`. If no such header exists, `header` is added as a header
506 /// to `self`.
507 ///
508 /// # Example
509 ///
510 /// ```rust
511 /// use rocket::http::ContentType;
512 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
513 /// # let mut req = c.get("/");
514 /// # let request = req.inner_mut();
515 ///
516 /// assert!(request.headers().is_empty());
517 ///
518 /// request.add_header(ContentType::Any);
519 /// assert_eq!(request.headers().get_one("Content-Type"), Some("*/*"));
520 /// assert_eq!(request.content_type(), Some(&ContentType::Any));
521 ///
522 /// request.replace_header(ContentType::PNG);
523 /// assert_eq!(request.headers().get_one("Content-Type"), Some("image/png"));
524 /// assert_eq!(request.content_type(), Some(&ContentType::PNG));
525 /// ```
526 #[inline]
527 pub fn replace_header<'h: 'r, H: Into<Header<'h>>>(&mut self, header: H) {
528 let header = header.into();
529 self.bust_header_cache(header.name(), true);
530 self.headers.replace(header);
531 }
532
533 /// Returns the Content-Type header of `self`. If the header is not present,
534 /// returns `None`.
535 ///
536 /// # Example
537 ///
538 /// ```rust
539 /// use rocket::http::ContentType;
540 ///
541 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
542 /// # let get = |uri| c.get(uri);
543 /// assert_eq!(get("/").content_type(), None);
544 ///
545 /// let req = get("/").header(ContentType::JSON);
546 /// assert_eq!(req.content_type(), Some(&ContentType::JSON));
547 /// ```
548 #[inline]
549 pub fn content_type(&self) -> Option<&ContentType> {
550 self.state.content_type.get_or_init(|| {
551 self.headers().get_one("Content-Type").and_then(|v| v.parse().ok())
552 }).as_ref()
553 }
554
555 /// Returns the Accept header of `self`. If the header is not present,
556 /// returns `None`.
557 ///
558 /// # Example
559 ///
560 /// ```rust
561 /// use rocket::http::Accept;
562 ///
563 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
564 /// # let get = |uri| c.get(uri);
565 /// assert_eq!(get("/").accept(), None);
566 /// assert_eq!(get("/").header(Accept::JSON).accept(), Some(&Accept::JSON));
567 /// ```
568 #[inline]
569 pub fn accept(&self) -> Option<&Accept> {
570 self.state.accept.get_or_init(|| {
571 self.headers().get_one("Accept").and_then(|v| v.parse().ok())
572 }).as_ref()
573 }
574
575 /// Returns the media type "format" of the request.
576 ///
577 /// The "format" of a request is either the Content-Type, if the request
578 /// methods indicates support for a payload, or the preferred media type in
579 /// the Accept header otherwise. If the method indicates no payload and no
580 /// Accept header is specified, a media type of `Any` is returned.
581 ///
582 /// The media type returned from this method is used to match against the
583 /// `format` route attribute.
584 ///
585 /// # Example
586 ///
587 /// ```rust
588 /// use rocket::http::{Accept, ContentType, MediaType};
589 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
590 /// # let get = |uri| c.get(uri);
591 /// # let post = |uri| c.post(uri);
592 ///
593 /// // Non-payload-bearing: format is accept header.
594 /// let req = get("/").header(Accept::HTML);
595 /// assert_eq!(req.format(), Some(&MediaType::HTML));
596 ///
597 /// let req = get("/").header(ContentType::JSON).header(Accept::HTML);
598 /// assert_eq!(req.format(), Some(&MediaType::HTML));
599 ///
600 /// // Payload: format is content-type header.
601 /// let req = post("/").header(ContentType::HTML);
602 /// assert_eq!(req.format(), Some(&MediaType::HTML));
603 ///
604 /// let req = post("/").header(ContentType::JSON).header(Accept::HTML);
605 /// assert_eq!(req.format(), Some(&MediaType::JSON));
606 ///
607 /// // Non-payload-bearing method and no accept header: `Any`.
608 /// assert_eq!(get("/").format(), Some(&MediaType::Any));
609 /// ```
610 pub fn format(&self) -> Option<&MediaType> {
611 static ANY: MediaType = MediaType::Any;
612 if self.method().supports_payload() {
613 self.content_type().map(|ct| ct.media_type())
614 } else {
615 // FIXME: Should we be using `accept_first` or `preferred`? Or
616 // should we be checking neither and instead pass things through
617 // where the client accepts the thing at all?
618 self.accept()
619 .map(|accept| accept.preferred().media_type())
620 .or(Some(&ANY))
621 }
622 }
623
624 /// Returns the [`Rocket`] instance that is handling this request.
625 ///
626 /// # Example
627 ///
628 /// ```rust
629 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
630 /// # let request = c.get("/");
631 /// # type Pool = usize;
632 /// // Retrieve the application config via `Rocket::config()`.
633 /// let config = request.rocket().config();
634 ///
635 /// // Retrieve managed state via `Rocket::state()`.
636 /// let state = request.rocket().state::<Pool>();
637 ///
638 /// // Get a list of all of the registered routes and catchers.
639 /// let routes = request.rocket().routes();
640 /// let catchers = request.rocket().catchers();
641 /// ```
642 #[inline(always)]
643 pub fn rocket(&self) -> &'r Rocket<Orbit> {
644 &self.state.rocket
645 }
646
647 /// Returns the configured application data limits.
648 ///
649 /// This is convenience function equivalent to:
650 ///
651 /// ```rust
652 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
653 /// # let request = c.get("/");
654 /// &request.rocket().config().limits
655 /// # ;
656 /// ```
657 ///
658 /// # Example
659 ///
660 /// ```rust
661 /// use rocket::data::ToByteUnit;
662 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
663 /// # let request = c.get("/");
664 ///
665 /// // This is the default `form` limit.
666 /// assert_eq!(request.limits().get("form"), Some(32.kibibytes()));
667 ///
668 /// // Retrieve the limit for files with extension `.pdf`; etails to 1MiB.
669 /// assert_eq!(request.limits().get("file/pdf"), Some(1.mebibytes()));
670 /// ```
671 #[inline(always)]
672 pub fn limits(&self) -> &'r Limits {
673 &self.rocket().config().limits
674 }
675
676 /// Get the presently matched route, if any.
677 ///
678 /// This method returns `Some` any time a handler or its guards are being
679 /// invoked. This method returns `None` _before_ routing has commenced; this
680 /// includes during request fairing callbacks.
681 ///
682 /// # Example
683 ///
684 /// ```rust
685 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
686 /// # let request = c.get("/");
687 /// let route = request.route();
688 /// ```
689 #[inline(always)]
690 pub fn route(&self) -> Option<&'r Route> {
691 self.state.route.load(Ordering::Acquire)
692 }
693
694 /// Invokes the request guard implementation for `T`, returning its outcome.
695 ///
696 /// # Example
697 ///
698 /// Assuming a `User` request guard exists, invoke it:
699 ///
700 /// ```rust
701 /// # type User = rocket::http::Method;
702 /// # rocket::async_test(async move {
703 /// # let c = rocket::local::asynchronous::Client::debug_with(vec![]).await.unwrap();
704 /// # let request = c.get("/");
705 /// let outcome = request.guard::<User>().await;
706 /// # })
707 /// ```
708 #[inline(always)]
709 pub fn guard<'z, 'a, T>(&'a self) -> BoxFuture<'z, Outcome<T, T::Error>>
710 where T: FromRequest<'a> + 'z, 'a: 'z, 'r: 'z
711 {
712 T::from_request(self)
713 }
714
715 /// Retrieves the cached value for type `T` from the request-local cached
716 /// state of `self`. If no such value has previously been cached for this
717 /// request, `f` is called to produce the value which is subsequently
718 /// returned.
719 ///
720 /// Different values of the same type _cannot_ be cached without using a
721 /// proxy, wrapper type. To avoid the need to write these manually, or for
722 /// libraries wishing to store values of public types, use the
723 /// [`local_cache!`](crate::request::local_cache) or
724 /// [`local_cache_once!`](crate::request::local_cache_once) macros to
725 /// generate a locally anonymous wrapper type, store, and retrieve the
726 /// wrapped value from request-local cache.
727 ///
728 /// # Example
729 ///
730 /// ```rust
731 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
732 /// # let request = c.get("/");
733 /// // The first store into local cache for a given type wins.
734 /// let value = request.local_cache(|| "hello");
735 /// assert_eq!(*request.local_cache(|| "hello"), "hello");
736 ///
737 /// // The following return the cached, previously stored value for the type.
738 /// assert_eq!(*request.local_cache(|| "goodbye"), "hello");
739 /// ```
740 #[inline]
741 pub fn local_cache<T, F>(&self, f: F) -> &T
742 where F: FnOnce() -> T,
743 T: Send + Sync + 'static
744 {
745 self.state.cache.try_get()
746 .unwrap_or_else(|| {
747 self.state.cache.set(f());
748 self.state.cache.get()
749 })
750 }
751
752 /// Retrieves the cached value for type `T` from the request-local cached
753 /// state of `self`. If no such value has previously been cached for this
754 /// request, `fut` is `await`ed to produce the value which is subsequently
755 /// returned.
756 ///
757 /// # Example
758 ///
759 /// ```rust
760 /// # use rocket::Request;
761 /// # type User = ();
762 /// async fn current_user<'r>(request: &Request<'r>) -> User {
763 /// // validate request for a given user, load from database, etc
764 /// }
765 ///
766 /// # rocket::async_test(async move {
767 /// # let c = rocket::local::asynchronous::Client::debug_with(vec![]).await.unwrap();
768 /// # let request = c.get("/");
769 /// let current_user = request.local_cache_async(async {
770 /// current_user(&request).await
771 /// }).await;
772 /// # })
773 /// ```
774 #[inline]
775 pub async fn local_cache_async<'a, T, F>(&'a self, fut: F) -> &'a T
776 where F: Future<Output = T>,
777 T: Send + Sync + 'static
778 {
779 match self.state.cache.try_get() {
780 Some(s) => s,
781 None => {
782 self.state.cache.set(fut.await);
783 self.state.cache.get()
784 }
785 }
786 }
787
788 /// Retrieves and parses into `T` the 0-indexed `n`th non-empty segment from
789 /// the _routed_ request, that is, the `n`th segment _after_ the mount
790 /// point. If the request has not been routed, then this is simply the `n`th
791 /// non-empty request URI segment.
792 ///
793 /// Returns `None` if `n` is greater than the number of non-empty segments.
794 /// Returns `Some(Err(T::Error))` if the parameter type `T` failed to be
795 /// parsed from the `n`th dynamic parameter.
796 ///
797 /// This method exists only to be used by manual routing. To retrieve
798 /// parameters from a request, use Rocket's code generation facilities.
799 ///
800 /// # Example
801 ///
802 /// ```rust
803 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
804 /// # let get = |uri| c.get(uri);
805 /// assert_eq!(get("/a/b/c").param(0), Some(Ok("a")));
806 /// assert_eq!(get("/a/b/c").param(1), Some(Ok("b")));
807 /// assert_eq!(get("/a/b/c").param(2), Some(Ok("c")));
808 /// assert_eq!(get("/a/b/c").param::<&str>(3), None);
809 ///
810 /// assert_eq!(get("/1/b/3").param(0), Some(Ok(1)));
811 /// assert!(get("/1/b/3").param::<usize>(1).unwrap().is_err());
812 /// assert_eq!(get("/1/b/3").param(2), Some(Ok(3)));
813 ///
814 /// assert_eq!(get("/").param::<&str>(0), None);
815 /// ```
816 #[inline]
817 pub fn param<'a, T>(&'a self, n: usize) -> Option<Result<T, T::Error>>
818 where T: FromParam<'a>
819 {
820 self.routed_segment(n).map(T::from_param)
821 }
822
823 /// Retrieves and parses into `T` all of the path segments in the request
824 /// URI beginning and including the 0-indexed `n`th non-empty segment
825 /// _after_ the mount point.,that is, the `n`th segment _after_ the mount
826 /// point. If the request has not been routed, then this is simply the `n`th
827 /// non-empty request URI segment.
828 ///
829 /// `T` must implement [`FromSegments`], which is used to parse the
830 /// segments. If there are no non-empty segments, the `Segments` iterator
831 /// will be empty.
832 ///
833 /// This method exists only to be used by manual routing. To retrieve
834 /// segments from a request, use Rocket's code generation facilities.
835 ///
836 /// # Example
837 ///
838 /// ```rust
839 /// use std::path::PathBuf;
840 ///
841 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
842 /// # let get = |uri| c.get(uri);
843 /// assert_eq!(get("/").segments(0..), Ok(PathBuf::new()));
844 /// assert_eq!(get("/").segments(2..), Ok(PathBuf::new()));
845 ///
846 /// // Empty segments are skipped.
847 /// assert_eq!(get("///").segments(2..), Ok(PathBuf::new()));
848 /// assert_eq!(get("/a/b/c").segments(0..), Ok(PathBuf::from("a/b/c")));
849 /// assert_eq!(get("/a/b/c").segments(1..), Ok(PathBuf::from("b/c")));
850 /// assert_eq!(get("/a/b/c").segments(2..), Ok(PathBuf::from("c")));
851 /// assert_eq!(get("/a/b/c").segments(3..), Ok(PathBuf::new()));
852 /// assert_eq!(get("/a/b/c").segments(4..), Ok(PathBuf::new()));
853 /// ```
854 #[inline]
855 pub fn segments<'a, T>(&'a self, n: RangeFrom<usize>) -> Result<T, T::Error>
856 where T: FromSegments<'a>
857 {
858 T::from_segments(self.routed_segments(n))
859 }
860
861 /// Retrieves and parses into `T` the query value with field name `name`.
862 /// `T` must implement [`FromForm`], which is used to parse the query's
863 /// value. Key matching is performed case-sensitively.
864 ///
865 /// # Warning
866 ///
867 /// This method exists _only_ to be used by manual routing and should
868 /// _never_ be used in a regular Rocket application. It is much more
869 /// expensive to use this method than to retrieve query parameters via
870 /// Rocket's codegen. To retrieve query values from a request, _always_
871 /// prefer to use Rocket's code generation facilities.
872 ///
873 /// # Error
874 ///
875 /// If a query segment with name `name` isn't present, returns `None`. If
876 /// parsing the value fails, returns `Some(Err(_))`.
877 ///
878 /// # Example
879 ///
880 /// ```rust
881 /// use rocket::form::FromForm;
882 ///
883 /// #[derive(Debug, PartialEq, FromForm)]
884 /// struct Dog<'r> {
885 /// name: &'r str,
886 /// age: usize
887 /// }
888 ///
889 /// # let c = rocket::local::blocking::Client::debug_with(vec![]).unwrap();
890 /// # let get = |uri| c.get(uri);
891 /// let req = get("/?a=apple&z=zebra&a=aardvark");
892 /// assert_eq!(req.query_value::<&str>("a").unwrap(), Ok("apple"));
893 /// assert_eq!(req.query_value::<&str>("z").unwrap(), Ok("zebra"));
894 /// assert_eq!(req.query_value::<&str>("b"), None);
895 ///
896 /// let a_seq = req.query_value::<Vec<&str>>("a");
897 /// assert_eq!(a_seq.unwrap().unwrap(), ["apple", "aardvark"]);
898 ///
899 /// let req = get("/?dog.name=Max+Fido&dog.age=3");
900 /// let dog = req.query_value::<Dog>("dog");
901 /// assert_eq!(dog.unwrap().unwrap(), Dog { name: "Max Fido", age: 3 });
902 /// ```
903 #[inline]
904 pub fn query_value<'a, T>(&'a self, name: &str) -> Option<form::Result<'a, T>>
905 where T: FromForm<'a>
906 {
907 if self.query_fields().find(|f| f.name == name).is_none() {
908 return None;
909 }
910
911 let mut ctxt = T::init(form::Options::Lenient);
912
913 self.query_fields()
914 .filter(|f| f.name == name)
915 .for_each(|f| T::push_value(&mut ctxt, f.shift()));
916
917 Some(T::finalize(ctxt))
918 }
919}
920
921// All of these methods only exist for internal, including codegen, purposes.
922// They _are not_ part of the stable API. Please, don't use these.
923#[doc(hidden)]
924impl<'r> Request<'r> {
925 /// Resets the cached value (if any) for the header with name `name`.
926 fn bust_header_cache(&mut self, name: &UncasedStr, replace: bool) {
927 if name == "Content-Type" {
928 if self.content_type().is_none() || replace {
929 self.state.content_type = InitCell::new();
930 }
931 } else if name == "Accept" {
932 if self.accept().is_none() || replace {
933 self.state.accept = InitCell::new();
934 }
935 }
936 }
937
938 /// Get the `n`th path segment, 0-indexed, after the mount point for the
939 /// currently matched route, as a string, if it exists. Used by codegen.
940 #[inline]
941 pub fn routed_segment(&self, n: usize) -> Option<&str> {
942 self.routed_segments(0..).get(n)
943 }
944
945 /// Get the segments beginning at the `n`th, 0-indexed, after the mount
946 /// point for the currently matched route, if they exist. Used by codegen.
947 #[inline]
948 pub fn routed_segments(&self, n: RangeFrom<usize>) -> Segments<'_, Path> {
949 let mount_segments = self.route()
950 .map(|r| r.uri.metadata.base_segs.len())
951 .unwrap_or(0);
952
953 self.uri().path().segments().skip(mount_segments + n.start)
954 }
955
956 // Retrieves the pre-parsed query items. Used by matching and codegen.
957 #[inline]
958 pub fn query_fields(&self) -> impl Iterator<Item = ValueField<'_>> {
959 self.uri().query()
960 .map(|q| q.segments().map(ValueField::from))
961 .into_iter()
962 .flatten()
963 }
964
965 /// Set `self`'s parameters given that the route used to reach this request
966 /// was `route`. Use during routing when attempting a given route.
967 #[inline(always)]
968 pub(crate) fn set_route(&self, route: &'r Route) {
969 self.state.route.store(Some(route), Ordering::Release)
970 }
971
972 /// Set the method of `self`, even when `self` is a shared reference. Used
973 /// during routing to override methods for re-routing.
974 #[inline(always)]
975 pub(crate) fn _set_method(&self, method: Method) {
976 self.method.store(method, Ordering::Release)
977 }
978
979 pub(crate) fn cookies_mut(&mut self) -> &mut CookieJar<'r> {
980 &mut self.state.cookies
981 }
982
983 /// Convert from Hyper types into a Rocket Request.
984 pub(crate) fn from_hyp(
985 rocket: &'r Rocket<Orbit>,
986 hyper: &'r hyper::request::Parts,
987 connection: Option<ConnectionMeta>,
988 ) -> Result<Request<'r>, BadRequest<'r>> {
989 // Keep track of parsing errors; emit a `BadRequest` if any exist.
990 let mut errors = vec![];
991
992 // Ensure that the method is known. TODO: Allow made-up methods?
993 let method = Method::from_hyp(&hyper.method)
994 .unwrap_or_else(|| {
995 errors.push(Kind::BadMethod(&hyper.method));
996 Method::Get
997 });
998
999 // TODO: Keep around not just the path/query, but the rest, if there?
1000 let uri = hyper.uri.path_and_query()
1001 .map(|uri| {
1002 // In debug, make sure we agree with Hyper about URI validity.
1003 // If we disagree, log a warning but continue anyway; if this is
1004 // a security issue with Hyper, there isn't much we can do.
1005 #[cfg(debug_assertions)]
1006 if Origin::parse(uri.as_str()).is_err() {
1007 warn!("Hyper/Rocket URI validity discord: {:?}", uri.as_str());
1008 info_!("Hyper believes the URI is valid while Rocket disagrees.");
1009 info_!("This is likely a Hyper bug with potential security implications.");
1010 warn_!("Please report this warning to Rocket's GitHub issue tracker.");
1011 }
1012
1013 Origin::new(uri.path(), uri.query().map(Cow::Borrowed))
1014 })
1015 .unwrap_or_else(|| {
1016 errors.push(Kind::InvalidUri(&hyper.uri));
1017 Origin::ROOT
1018 });
1019
1020 // Construct the request object; fill in metadata and headers next.
1021 let mut request = Request::new(rocket, method, uri);
1022
1023 // Set the passed in connection metadata.
1024 if let Some(connection) = connection {
1025 request.connection = connection;
1026 }
1027
1028 // Determine + set host. On HTTP < 2, use the `HOST` header. Otherwise,
1029 // use the `:authority` pseudo-header which hyper makes part of the URI.
1030 request.state.host = if hyper.version < hyper::Version::HTTP_2 {
1031 hyper.headers.get("host").and_then(|h| Host::parse_bytes(h.as_bytes()).ok())
1032 } else {
1033 hyper.uri.host().map(|h| Host::new(Authority::new(None, h, hyper.uri.port_u16())))
1034 };
1035
1036 // Set the request cookies, if they exist.
1037 for header in hyper.headers.get_all("Cookie") {
1038 let raw_str = match std::str::from_utf8(header.as_bytes()) {
1039 Ok(string) => string,
1040 Err(_) => continue
1041 };
1042
1043 for cookie_str in raw_str.split(';').map(|s| s.trim()) {
1044 if let Ok(cookie) = Cookie::parse_encoded(cookie_str) {
1045 request.state.cookies.add_original(cookie.into_owned());
1046 }
1047 }
1048 }
1049
1050 // Set the rest of the headers. This is rather unfortunate and slow.
1051 for (name, value) in hyper.headers.iter() {
1052 // FIXME: This is rather unfortunate. Header values needn't be UTF8.
1053 let value = match std::str::from_utf8(value.as_bytes()) {
1054 Ok(value) => value,
1055 Err(_) => {
1056 warn!("Header '{}' contains invalid UTF-8", name);
1057 warn_!("Rocket only supports UTF-8 header values. Dropping header.");
1058 continue;
1059 }
1060 };
1061
1062 request.add_header(Header::new(name.as_str(), value));
1063 }
1064
1065 if errors.is_empty() {
1066 Ok(request)
1067 } else {
1068 Err(BadRequest { request, errors })
1069 }
1070 }
1071}
1072
1073#[derive(Debug)]
1074pub(crate) struct BadRequest<'r> {
1075 pub request: Request<'r>,
1076 pub errors: Vec<Kind<'r>>,
1077}
1078
1079#[derive(Debug)]
1080pub(crate) enum Kind<'r> {
1081 InvalidUri(&'r hyper::Uri),
1082 BadMethod(&'r hyper::Method),
1083}
1084
1085impl fmt::Display for Kind<'_> {
1086 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1087 match self {
1088 Kind::InvalidUri(u) => write!(f, "invalid origin URI: {}", u),
1089 Kind::BadMethod(m) => write!(f, "invalid or unrecognized method: {}", m),
1090 }
1091 }
1092}
1093
1094impl fmt::Debug for Request<'_> {
1095 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1096 fmt.debug_struct("Request")
1097 .field("method", &self.method)
1098 .field("uri", &self.uri)
1099 .field("headers", &self.headers())
1100 .field("remote", &self.remote())
1101 .field("cookies", &self.cookies())
1102 .finish()
1103 }
1104}
1105
1106impl fmt::Display for Request<'_> {
1107 /// Pretty prints a Request. Primarily used by Rocket's logging.
1108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1109 write!(f, "{} {}", self.method().green(), self.uri.blue())?;
1110
1111 // Print the requests media type when the route specifies a format.
1112 if let Some(mime) = self.format() {
1113 if !mime.is_any() {
1114 write!(f, " {}/{}", mime.top().yellow().linger(), mime.sub().resetting())?;
1115 }
1116 }
1117
1118 Ok(())
1119 }
1120}