rocket_community/request/
request.rs

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