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}