1 use std::rc::Rc;
2 use std::cell::{Cell, RefCell};
3 use std::net::{IpAddr, SocketAddr};
4 use std::fmt;
5 use std::str;
6
7 use yansi::Paint;
8 use state::{Container, Storage};
9
10 use crate::request::{FromParam, FromSegments, FromRequest, Outcome};
11 use crate::request::{FromFormValue, FormItems, FormItem};
12
13 use crate::rocket::Rocket;
14 use crate::router::Route;
15 use crate::config::{Config, Limits};
16 use crate::http::{hyper, uri::{Origin, Segments}};
17 use crate::http::{Method, Header, HeaderMap, Cookies};
18 use crate::http::{RawStr, ContentType, Accept, MediaType};
19 use crate::http::private::{Indexed, SmallVec, CookieJar};
20
21 type Indices = (usize, usize);
22
23 /// The type of an incoming web request.
24 ///
25 /// This should be used sparingly in Rocket applications. In particular, it
26 /// should likely only be used when writing [`FromRequest`] implementations. It
27 /// contains all of the information for a given web request except for the body
28 /// data. This includes the HTTP method, URI, cookies, headers, and more.
29 #[derive(Clone)]
30 pub struct Request<'r> {
31 method: Cell<Method>,
32 uri: Origin<'r>,
33 headers: HeaderMap<'r>,
34 remote: Option<SocketAddr>,
35 pub(crate) state: RequestState<'r>,
36 }
37
38 #[derive(Clone)]
39 pub(crate) struct RequestState<'r> {
40 pub config: &'r Config,
41 pub managed: &'r Container,
42 pub path_segments: SmallVec<[Indices; 12]>,
43 pub query_items: Option<SmallVec<[IndexedFormItem; 6]>>,
44 pub route: Cell<Option<&'r Route>>,
45 pub cookies: RefCell<CookieJar>,
46 pub accept: Storage<Option<Accept>>,
47 pub content_type: Storage<Option<ContentType>>,
48 pub cache: Rc<Container>,
49 }
50
51 #[derive(Clone)]
52 pub(crate) struct IndexedFormItem {
53 raw: Indices,
54 key: Indices,
55 value: Indices
56 }
57
58 impl<'r> Request<'r> {
59 /// Create a new `Request` with the given `method` and `uri`.
60 #[inline(always)]
new<'s: 'r>( rocket: &'r Rocket, method: Method, uri: Origin<'s> ) -> Request<'r>61 pub(crate) fn new<'s: 'r>(
62 rocket: &'r Rocket,
63 method: Method,
64 uri: Origin<'s>
65 ) -> Request<'r> {
66 let mut request = Request {
67 method: Cell::new(method),
68 uri: uri,
69 headers: HeaderMap::new(),
70 remote: None,
71 state: RequestState {
72 path_segments: SmallVec::new(),
73 query_items: None,
74 config: &rocket.config,
75 managed: &rocket.state,
76 route: Cell::new(None),
77 cookies: RefCell::new(CookieJar::new()),
78 accept: Storage::new(),
79 content_type: Storage::new(),
80 cache: Rc::new(Container::new()),
81 }
82 };
83
84 request.update_cached_uri_info();
85 request
86 }
87
88 /// Retrieve the method from `self`.
89 ///
90 /// # Example
91 ///
92 /// ```rust
93 /// # use rocket::Request;
94 /// use rocket::http::Method;
95 ///
96 /// # Request::example(Method::Get, "/uri", |request| {
97 /// request.set_method(Method::Get);
98 /// assert_eq!(request.method(), Method::Get);
99 /// # });
100 /// ```
101 #[inline(always)]
method(&self) -> Method102 pub fn method(&self) -> Method {
103 self.method.get()
104 }
105
106 /// Set the method of `self`.
107 ///
108 /// # Example
109 ///
110 /// ```rust
111 /// # use rocket::Request;
112 /// use rocket::http::Method;
113 ///
114 /// # Request::example(Method::Get, "/uri", |request| {
115 /// assert_eq!(request.method(), Method::Get);
116 ///
117 /// request.set_method(Method::Post);
118 /// assert_eq!(request.method(), Method::Post);
119 /// # });
120 /// ```
121 #[inline(always)]
set_method(&mut self, method: Method)122 pub fn set_method(&mut self, method: Method) {
123 self._set_method(method);
124 }
125
126 /// Borrow the [`Origin`] URI from `self`.
127 ///
128 /// # Example
129 ///
130 /// ```rust
131 /// # use rocket::Request;
132 /// # use rocket::http::Method;
133 /// # Request::example(Method::Get, "/uri", |request| {
134 /// assert_eq!(request.uri().path(), "/uri");
135 /// # });
136 /// ```
137 #[inline(always)]
uri(&self) -> &Origin<'_>138 pub fn uri(&self) -> &Origin<'_> {
139 &self.uri
140 }
141
142 /// Set the URI in `self` to `uri`.
143 ///
144 /// # Example
145 ///
146 /// ```rust
147 /// use rocket::http::uri::Origin;
148 ///
149 /// # use rocket::Request;
150 /// # use rocket::http::Method;
151 /// # Request::example(Method::Get, "/uri", |mut request| {
152 /// let uri = Origin::parse("/hello/Sergio?type=greeting").unwrap();
153 /// request.set_uri(uri);
154 /// assert_eq!(request.uri().path(), "/hello/Sergio");
155 /// assert_eq!(request.uri().query(), Some("type=greeting"));
156 /// # });
157 /// ```
set_uri<'u: 'r>(&mut self, uri: Origin<'u>)158 pub fn set_uri<'u: 'r>(&mut self, uri: Origin<'u>) {
159 self.uri = uri;
160 self.update_cached_uri_info();
161 }
162
163 /// Returns the address of the remote connection that initiated this
164 /// request if the address is known. If the address is not known, `None` is
165 /// returned.
166 ///
167 /// Because it is common for proxies to forward connections for clients, the
168 /// remote address may contain information about the proxy instead of the
169 /// client. For this reason, proxies typically set the "X-Real-IP" header
170 /// with the client's true IP. To extract this IP from the request, use the
171 /// [`real_ip()`] or [`client_ip()`] methods.
172 ///
173 /// [`real_ip()`]: #method.real_ip
174 /// [`client_ip()`]: #method.client_ip
175 ///
176 /// # Example
177 ///
178 /// ```rust
179 /// # use rocket::Request;
180 /// # use rocket::http::Method;
181 /// # Request::example(Method::Get, "/uri", |request| {
182 /// assert!(request.remote().is_none());
183 /// # });
184 /// ```
185 #[inline(always)]
remote(&self) -> Option<SocketAddr>186 pub fn remote(&self) -> Option<SocketAddr> {
187 self.remote
188 }
189
190 /// Sets the remote address of `self` to `address`.
191 ///
192 /// # Example
193 ///
194 /// Set the remote address to be 127.0.0.1:8000:
195 ///
196 /// ```rust
197 /// # use rocket::Request;
198 /// # use rocket::http::Method;
199 /// use std::net::{SocketAddr, IpAddr, Ipv4Addr};
200 ///
201 /// # Request::example(Method::Get, "/uri", |mut request| {
202 /// let (ip, port) = (IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8000);
203 /// let localhost = SocketAddr::new(ip, port);
204 /// request.set_remote(localhost);
205 ///
206 /// assert_eq!(request.remote(), Some(localhost));
207 /// # });
208 /// ```
209 #[inline(always)]
set_remote(&mut self, address: SocketAddr)210 pub fn set_remote(&mut self, address: SocketAddr) {
211 self.remote = Some(address);
212 }
213
214 /// Returns the IP address in the "X-Real-IP" header of the request if such
215 /// a header exists and contains a valid IP address.
216 ///
217 /// # Example
218 ///
219 /// ```rust
220 /// # use rocket::Request;
221 /// # use rocket::http::{Header, Method};
222 /// # use std::net::{SocketAddr, IpAddr, Ipv4Addr};
223 ///
224 /// # Request::example(Method::Get, "/uri", |mut request| {
225 /// request.add_header(Header::new("X-Real-IP", "8.8.8.8"));
226 /// assert_eq!(request.real_ip(), Some("8.8.8.8".parse().unwrap()));
227 /// # });
228 /// ```
real_ip(&self) -> Option<IpAddr>229 pub fn real_ip(&self) -> Option<IpAddr> {
230 self.headers()
231 .get_one("X-Real-IP")
232 .and_then(|ip| {
233 ip.parse()
234 .map_err(|_| warn_!("'X-Real-IP' header is malformed: {}", ip))
235 .ok()
236 })
237 }
238
239 /// Attempts to return the client's IP address by first inspecting the
240 /// "X-Real-IP" header and then using the remote connection's IP address.
241 ///
242 /// If the "X-Real-IP" header exists and contains a valid IP address, that
243 /// address is returned. Otherwise, if the address of the remote connection
244 /// is known, that address is returned. Otherwise, `None` is returned.
245 ///
246 /// # Example
247 ///
248 /// ```rust
249 /// # use rocket::Request;
250 /// # use rocket::http::{Header, Method};
251 /// # use std::net::{SocketAddr, IpAddr, Ipv4Addr};
252 ///
253 /// # Request::example(Method::Get, "/uri", |mut request| {
254 /// // starting without an "X-Real-IP" header or remote addresss
255 /// assert!(request.client_ip().is_none());
256 ///
257 /// // add a remote address; this is done by Rocket automatically
258 /// request.set_remote("127.0.0.1:8000".parse().unwrap());
259 /// assert_eq!(request.client_ip(), Some("127.0.0.1".parse().unwrap()));
260 ///
261 /// // now with an X-Real-IP header
262 /// request.add_header(Header::new("X-Real-IP", "8.8.8.8"));
263 /// assert_eq!(request.client_ip(), Some("8.8.8.8".parse().unwrap()));
264 /// # });
265 /// ```
266 #[inline]
client_ip(&self) -> Option<IpAddr>267 pub fn client_ip(&self) -> Option<IpAddr> {
268 self.real_ip().or_else(|| self.remote().map(|r| r.ip()))
269 }
270
271 /// Returns a wrapped borrow to the cookies in `self`.
272 ///
273 /// [`Cookies`] implements internal mutability, so this method allows you to
274 /// get _and_ add/remove cookies in `self`.
275 ///
276 /// # Example
277 ///
278 /// Add a new cookie to a request's cookies:
279 ///
280 /// ```rust
281 /// # use rocket::Request;
282 /// # use rocket::http::Method;
283 /// use rocket::http::Cookie;
284 ///
285 /// # Request::example(Method::Get, "/uri", |mut request| {
286 /// request.cookies().add(Cookie::new("key", "val"));
287 /// request.cookies().add(Cookie::new("ans", format!("life: {}", 38 + 4)));
288 /// # });
289 /// ```
cookies(&self) -> Cookies<'_>290 pub fn cookies(&self) -> Cookies<'_> {
291 // FIXME: Can we do better? This is disappointing.
292 match self.state.cookies.try_borrow_mut() {
293 Ok(jar) => Cookies::new(jar, self.state.config.secret_key()),
294 Err(_) => {
295 error_!("Multiple `Cookies` instances are active at once.");
296 info_!("An instance of `Cookies` must be dropped before another \
297 can be retrieved.");
298 warn_!("The retrieved `Cookies` instance will be empty.");
299 Cookies::empty()
300 }
301 }
302 }
303
304 /// Returns a [`HeaderMap`] of all of the headers in `self`.
305 ///
306 /// # Example
307 ///
308 /// ```rust
309 /// # use rocket::Request;
310 /// # use rocket::http::Method;
311 /// # Request::example(Method::Get, "/uri", |request| {
312 /// let header_map = request.headers();
313 /// assert!(header_map.is_empty());
314 /// # });
315 /// ```
316 #[inline(always)]
headers(&self) -> &HeaderMap<'r>317 pub fn headers(&self) -> &HeaderMap<'r> {
318 &self.headers
319 }
320
321 /// Add `header` to `self`'s headers. The type of `header` can be any type
322 /// that implements the `Into<Header>` trait. This includes common types
323 /// such as [`ContentType`] and [`Accept`].
324 ///
325 /// # Example
326 ///
327 /// ```rust
328 /// # use rocket::Request;
329 /// # use rocket::http::Method;
330 /// use rocket::http::ContentType;
331 ///
332 /// # Request::example(Method::Get, "/uri", |mut request| {
333 /// assert!(request.headers().is_empty());
334 ///
335 /// request.add_header(ContentType::HTML);
336 /// assert!(request.headers().contains("Content-Type"));
337 /// assert_eq!(request.headers().len(), 1);
338 /// # });
339 /// ```
340 #[inline(always)]
add_header<'h: 'r, H: Into<Header<'h>>>(&mut self, header: H)341 pub fn add_header<'h: 'r, H: Into<Header<'h>>>(&mut self, header: H) {
342 self.headers.add(header.into());
343 }
344
345 /// Replaces the value of the header with name `header.name` with
346 /// `header.value`. If no such header exists, `header` is added as a header
347 /// to `self`.
348 ///
349 /// # Example
350 ///
351 /// ```rust
352 /// # use rocket::Request;
353 /// # use rocket::http::Method;
354 /// use rocket::http::ContentType;
355 ///
356 /// # Request::example(Method::Get, "/uri", |mut request| {
357 /// assert!(request.headers().is_empty());
358 ///
359 /// request.add_header(ContentType::Any);
360 /// assert_eq!(request.headers().get_one("Content-Type"), Some("*/*"));
361 ///
362 /// request.replace_header(ContentType::PNG);
363 /// assert_eq!(request.headers().get_one("Content-Type"), Some("image/png"));
364 /// # });
365 /// ```
366 #[inline(always)]
replace_header<'h: 'r, H: Into<Header<'h>>>(&mut self, header: H)367 pub fn replace_header<'h: 'r, H: Into<Header<'h>>>(&mut self, header: H) {
368 self.headers.replace(header.into());
369 }
370
371 /// Returns the Content-Type header of `self`. If the header is not present,
372 /// returns `None`. The Content-Type header is cached after the first call
373 /// to this function. As a result, subsequent calls will always return the
374 /// same value.
375 ///
376 /// # Example
377 ///
378 /// ```rust
379 /// # use rocket::Request;
380 /// # use rocket::http::Method;
381 /// use rocket::http::ContentType;
382 ///
383 /// # Request::example(Method::Get, "/uri", |mut request| {
384 /// request.add_header(ContentType::JSON);
385 /// assert_eq!(request.content_type(), Some(&ContentType::JSON));
386 ///
387 /// // The header is cached; it cannot be replaced after first access.
388 /// request.replace_header(ContentType::HTML);
389 /// assert_eq!(request.content_type(), Some(&ContentType::JSON));
390 /// # });
391 /// ```
392 #[inline(always)]
content_type(&self) -> Option<&ContentType>393 pub fn content_type(&self) -> Option<&ContentType> {
394 self.state.content_type.get_or_set(|| {
395 self.headers().get_one("Content-Type").and_then(|v| v.parse().ok())
396 }).as_ref()
397 }
398
399 /// Returns the Accept header of `self`. If the header is not present,
400 /// returns `None`. The Accept header is cached after the first call to this
401 /// function. As a result, subsequent calls will always return the same
402 /// value.
403 ///
404 /// # Example
405 ///
406 /// ```rust
407 /// # use rocket::Request;
408 /// # use rocket::http::Method;
409 /// use rocket::http::Accept;
410 ///
411 /// # Request::example(Method::Get, "/uri", |mut request| {
412 /// request.add_header(Accept::JSON);
413 /// assert_eq!(request.accept(), Some(&Accept::JSON));
414 ///
415 /// // The header is cached; it cannot be replaced after first access.
416 /// request.replace_header(Accept::HTML);
417 /// assert_eq!(request.accept(), Some(&Accept::JSON));
418 /// # });
419 /// ```
420 #[inline(always)]
accept(&self) -> Option<&Accept>421 pub fn accept(&self) -> Option<&Accept> {
422 self.state.accept.get_or_set(|| {
423 self.headers().get_one("Accept").and_then(|v| v.parse().ok())
424 }).as_ref()
425 }
426
427 /// Returns the media type "format" of the request.
428 ///
429 /// The "format" of a request is either the Content-Type, if the request
430 /// methods indicates support for a payload, or the preferred media type in
431 /// the Accept header otherwise. If the method indicates no payload and no
432 /// Accept header is specified, a media type of `Any` is returned.
433 ///
434 /// The media type returned from this method is used to match against the
435 /// `format` route attribute.
436 ///
437 /// # Example
438 ///
439 /// ```rust
440 /// # use rocket::Request;
441 /// use rocket::http::{Method, Accept, ContentType, MediaType};
442 ///
443 /// # Request::example(Method::Get, "/uri", |mut request| {
444 /// request.add_header(ContentType::JSON);
445 /// request.add_header(Accept::HTML);
446 ///
447 /// request.set_method(Method::Get);
448 /// assert_eq!(request.format(), Some(&MediaType::HTML));
449 ///
450 /// request.set_method(Method::Post);
451 /// assert_eq!(request.format(), Some(&MediaType::JSON));
452 /// # });
453 /// ```
format(&self) -> Option<&MediaType>454 pub fn format(&self) -> Option<&MediaType> {
455 static ANY: MediaType = MediaType::Any;
456 if self.method().supports_payload() {
457 self.content_type().map(|ct| ct.media_type())
458 } else {
459 // FIXME: Should we be using `accept_first` or `preferred`? Or
460 // should we be checking neither and instead pass things through
461 // where the client accepts the thing at all?
462 self.accept()
463 .map(|accept| accept.preferred().media_type())
464 .or(Some(&ANY))
465 }
466 }
467
468 /// Returns the configured application receive limits.
469 ///
470 /// # Example
471 ///
472 /// ```rust
473 /// # use rocket::Request;
474 /// # use rocket::http::Method;
475 /// # Request::example(Method::Get, "/uri", |mut request| {
476 /// let json_limit = request.limits().get("json");
477 /// # });
478 /// ```
limits(&self) -> &'r Limits479 pub fn limits(&self) -> &'r Limits {
480 &self.state.config.limits
481 }
482
483 /// Get the presently matched route, if any.
484 ///
485 /// This method returns `Some` any time a handler or its guards are being
486 /// invoked. This method returns `None` _before_ routing has commenced; this
487 /// includes during request fairing callbacks.
488 ///
489 /// # Example
490 ///
491 /// ```rust
492 /// # use rocket::Request;
493 /// # use rocket::http::Method;
494 /// # Request::example(Method::Get, "/uri", |mut request| {
495 /// let route = request.route();
496 /// # });
497 /// ```
route(&self) -> Option<&'r Route>498 pub fn route(&self) -> Option<&'r Route> {
499 self.state.route.get()
500 }
501
502 /// Invokes the request guard implementation for `T`, returning its outcome.
503 ///
504 /// # Example
505 ///
506 /// Assuming a `User` request guard exists, invoke it:
507 ///
508 /// ```rust
509 /// # use rocket::Request;
510 /// # use rocket::http::Method;
511 /// # type User = Method;
512 /// # Request::example(Method::Get, "/uri", |request| {
513 /// let outcome = request.guard::<User>();
514 /// # });
515 /// ```
516 ///
517 /// Retrieve managed state inside of a guard implementation:
518 ///
519 /// ```rust
520 /// # use rocket::Request;
521 /// # use rocket::http::Method;
522 /// use rocket::State;
523 ///
524 /// # type Pool = usize;
525 /// # Request::example(Method::Get, "/uri", |request| {
526 /// let pool = request.guard::<State<Pool>>();
527 /// # });
528 /// ```
529 #[inline(always)]
guard<'a, T: FromRequest<'a, 'r>>(&'a self) -> Outcome<T, T::Error>530 pub fn guard<'a, T: FromRequest<'a, 'r>>(&'a self) -> Outcome<T, T::Error> {
531 T::from_request(self)
532 }
533
534 /// Retrieves the cached value for type `T` from the request-local cached
535 /// state of `self`. If no such value has previously been cached for this
536 /// request, `f` is called to produce the value which is subsequently
537 /// returned.
538 ///
539 /// # Example
540 ///
541 /// ```rust
542 /// # use rocket::http::Method;
543 /// # use rocket::Request;
544 /// # type User = ();
545 /// fn current_user(request: &Request) -> User {
546 /// // Validate request for a given user, load from database, etc.
547 /// }
548 ///
549 /// # Request::example(Method::Get, "/uri", |request| {
550 /// let user = request.local_cache(|| current_user(request));
551 /// # });
552 /// ```
local_cache<T, F>(&self, f: F) -> &T where F: FnOnce() -> T, T: Send + Sync + 'static553 pub fn local_cache<T, F>(&self, f: F) -> &T
554 where F: FnOnce() -> T,
555 T: Send + Sync + 'static
556 {
557 self.state.cache.try_get()
558 .unwrap_or_else(|| {
559 self.state.cache.set(f());
560 self.state.cache.get()
561 })
562 }
563
564 /// Retrieves and parses into `T` the 0-indexed `n`th segment from the
565 /// request. Returns `None` if `n` is greater than the number of segments.
566 /// Returns `Some(Err(T::Error))` if the parameter type `T` failed to be
567 /// parsed from the `n`th dynamic parameter.
568 ///
569 /// This method exists only to be used by manual routing. To retrieve
570 /// parameters from a request, use Rocket's code generation facilities.
571 ///
572 /// # Example
573 ///
574 /// ```rust
575 /// # use rocket::{Request, http::Method};
576 /// use rocket::http::{RawStr, uri::Origin};
577 ///
578 /// # Request::example(Method::Get, "/", |req| {
579 /// fn string<'s>(req: &'s mut Request, uri: &'static str, n: usize) -> &'s RawStr {
580 /// req.set_uri(Origin::parse(uri).unwrap());
581 ///
582 /// req.get_param(n)
583 /// .and_then(|r| r.ok())
584 /// .unwrap_or("unnamed".into())
585 /// }
586 ///
587 /// assert_eq!(string(req, "/", 0).as_str(), "unnamed");
588 /// assert_eq!(string(req, "/a/b/this_one", 0).as_str(), "a");
589 /// assert_eq!(string(req, "/a/b/this_one", 1).as_str(), "b");
590 /// assert_eq!(string(req, "/a/b/this_one", 2).as_str(), "this_one");
591 /// assert_eq!(string(req, "/a/b/this_one", 3).as_str(), "unnamed");
592 /// assert_eq!(string(req, "/a/b/c/d/e/f/g/h", 7).as_str(), "h");
593 /// # });
594 /// ```
595 #[inline]
get_param<'a, T>(&'a self, n: usize) -> Option<Result<T, T::Error>> where T: FromParam<'a>596 pub fn get_param<'a, T>(&'a self, n: usize) -> Option<Result<T, T::Error>>
597 where T: FromParam<'a>
598 {
599 Some(T::from_param(self.raw_segment_str(n)?))
600 }
601
602 /// Retrieves and parses into `T` all of the path segments in the request
603 /// URI beginning and including the 0-indexed `n`th non-empty segment. `T`
604 /// must implement [`FromSegments`], which is used to parse the segments.
605 ///
606 /// This method exists only to be used by manual routing. To retrieve
607 /// segments from a request, use Rocket's code generation facilities.
608 ///
609 /// # Error
610 ///
611 /// If there are fewer than `n` non-empty segments, returns `None`. If
612 /// parsing the segments failed, returns `Some(Err(T:Error))`.
613 ///
614 /// # Example
615 ///
616 /// ```rust
617 /// # use rocket::{Request, http::Method};
618 /// use std::path::PathBuf;
619 ///
620 /// use rocket::http::uri::Origin;
621 ///
622 /// # Request::example(Method::Get, "/", |req| {
623 /// fn path<'s>(req: &'s mut Request, uri: &'static str, n: usize) -> PathBuf {
624 /// req.set_uri(Origin::parse(uri).unwrap());
625 ///
626 /// req.get_segments(n)
627 /// .and_then(|r| r.ok())
628 /// .unwrap_or_else(|| "whoops".into())
629 /// }
630 ///
631 /// assert_eq!(path(req, "/", 0), PathBuf::from("whoops"));
632 /// assert_eq!(path(req, "/a/", 0), PathBuf::from("a"));
633 /// assert_eq!(path(req, "/a/b/c", 0), PathBuf::from("a/b/c"));
634 /// assert_eq!(path(req, "/a/b/c", 1), PathBuf::from("b/c"));
635 /// assert_eq!(path(req, "/a/b/c", 2), PathBuf::from("c"));
636 /// assert_eq!(path(req, "/a/b/c", 6), PathBuf::from("whoops"));
637 /// # });
638 /// ```
639 #[inline]
get_segments<'a, T>(&'a self, n: usize) -> Option<Result<T, T::Error>> where T: FromSegments<'a>640 pub fn get_segments<'a, T>(&'a self, n: usize) -> Option<Result<T, T::Error>>
641 where T: FromSegments<'a>
642 {
643 Some(T::from_segments(self.raw_segments(n)?))
644 }
645
646 /// Retrieves and parses into `T` the query value with key `key`. `T` must
647 /// implement [`FromFormValue`], which is used to parse the query's value.
648 /// Key matching is performed case-sensitively. If there are multiple pairs
649 /// with key `key`, the _last_ one is returned.
650 ///
651 /// This method exists only to be used by manual routing. To retrieve
652 /// query values from a request, use Rocket's code generation facilities.
653 ///
654 /// # Error
655 ///
656 /// If a query segment with key `key` isn't present, returns `None`. If
657 /// parsing the value fails, returns `Some(Err(T:Error))`.
658 ///
659 /// # Example
660 ///
661 /// ```rust
662 /// # use rocket::{Request, http::Method};
663 /// use std::path::PathBuf;
664 /// use rocket::http::{RawStr, uri::Origin};
665 ///
666 /// # Request::example(Method::Get, "/", |req| {
667 /// fn value<'s>(req: &'s mut Request, uri: &'static str, key: &str) -> &'s RawStr {
668 /// req.set_uri(Origin::parse(uri).unwrap());
669 ///
670 /// req.get_query_value(key)
671 /// .and_then(|r| r.ok())
672 /// .unwrap_or("n/a".into())
673 /// }
674 ///
675 /// assert_eq!(value(req, "/?a=apple&z=zebra", "a").as_str(), "apple");
676 /// assert_eq!(value(req, "/?a=apple&z=zebra", "z").as_str(), "zebra");
677 /// assert_eq!(value(req, "/?a=apple&z=zebra", "A").as_str(), "n/a");
678 /// assert_eq!(value(req, "/?a=apple&z=zebra&a=argon", "a").as_str(), "argon");
679 /// assert_eq!(value(req, "/?a=1&a=2&a=3&b=4", "a").as_str(), "3");
680 /// assert_eq!(value(req, "/?a=apple&z=zebra", "apple").as_str(), "n/a");
681 /// # });
682 /// ```
683 #[inline]
get_query_value<'a, T>(&'a self, key: &str) -> Option<Result<T, T::Error>> where T: FromFormValue<'a>684 pub fn get_query_value<'a, T>(&'a self, key: &str) -> Option<Result<T, T::Error>>
685 where T: FromFormValue<'a>
686 {
687 self.raw_query_items()?
688 .rev()
689 .find(|item| item.key.as_str() == key)
690 .map(|item| T::from_form_value(item.value))
691 }
692 }
693
694 // All of these methods only exist for internal, including codegen, purposes.
695 // They _are not_ part of the stable API.
696 #[doc(hidden)]
697 impl<'r> Request<'r> {
698 // Only used by doc-tests! Needs to be `pub` because doc-test are external.
example<F: Fn(&mut Request<'_>)>(method: Method, uri: &str, f: F)699 pub fn example<F: Fn(&mut Request<'_>)>(method: Method, uri: &str, f: F) {
700 let rocket = Rocket::custom(Config::development());
701 let uri = Origin::parse(uri).expect("invalid URI in example");
702 let mut request = Request::new(&rocket, method, uri);
703 f(&mut request);
704 }
705
706 // Updates the cached `path_segments` and `query_items` in `self.state`.
707 // MUST be called whenever a new URI is set or updated.
708 #[inline]
update_cached_uri_info(&mut self)709 fn update_cached_uri_info(&mut self) {
710 let path_segments = Segments(self.uri.path())
711 .map(|s| indices(s, self.uri.path()))
712 .collect();
713
714 let query_items = self.uri.query()
715 .map(|query_str| FormItems::from(query_str)
716 .map(|item| IndexedFormItem::from(query_str, item))
717 .collect()
718 );
719
720 self.state.path_segments = path_segments;
721 self.state.query_items = query_items;
722 }
723
724 /// Get the `n`th path segment, 0-indexed, after the mount point for the
725 /// currently matched route, as a string, if it exists. Used by codegen.
726 #[inline]
raw_segment_str(&self, n: usize) -> Option<&RawStr>727 pub fn raw_segment_str(&self, n: usize) -> Option<&RawStr> {
728 self.routed_path_segment(n)
729 .map(|(i, j)| self.uri.path()[i..j].into())
730 }
731
732 /// Get the segments beginning at the `n`th, 0-indexed, after the mount
733 /// point for the currently matched route, if they exist. Used by codegen.
734 #[inline]
raw_segments(&self, n: usize) -> Option<Segments<'_>>735 pub fn raw_segments(&self, n: usize) -> Option<Segments<'_>> {
736 self.routed_path_segment(n)
737 .map(|(i, _)| Segments(&self.uri.path()[i..]) )
738 }
739
740 // Returns an iterator over the raw segments of the path URI. Does not take
741 // into account the current route. This is used during routing.
742 #[inline]
raw_path_segments(&self) -> impl Iterator<Item = &RawStr>743 pub(crate) fn raw_path_segments(&self) -> impl Iterator<Item = &RawStr> {
744 let path = self.uri.path();
745 self.state.path_segments.iter().cloned()
746 .map(move |(i, j)| path[i..j].into())
747 }
748
749 #[inline]
routed_path_segment(&self, n: usize) -> Option<(usize, usize)>750 fn routed_path_segment(&self, n: usize) -> Option<(usize, usize)> {
751 let mount_segments = self.route()
752 .map(|r| r.base.segment_count())
753 .unwrap_or(0);
754
755 self.state.path_segments.get(mount_segments + n).map(|(i, j)| (*i, *j))
756 }
757
758 // Retrieves the pre-parsed query items. Used by matching and codegen.
759 #[inline]
raw_query_items( &self ) -> Option<impl Iterator<Item = FormItem<'_>> + DoubleEndedIterator + Clone>760 pub fn raw_query_items(
761 &self
762 ) -> Option<impl Iterator<Item = FormItem<'_>> + DoubleEndedIterator + Clone> {
763 let query = self.uri.query()?;
764 self.state.query_items.as_ref().map(move |items| {
765 items.iter().map(move |item| item.convert(query))
766 })
767 }
768
769 /// Set `self`'s parameters given that the route used to reach this request
770 /// was `route`. Use during routing when attempting a given route.
771 #[inline(always)]
set_route(&self, route: &'r Route)772 pub(crate) fn set_route(&self, route: &'r Route) {
773 self.state.route.set(Some(route));
774 }
775
776 /// Set the method of `self`, even when `self` is a shared reference. Used
777 /// during routing to override methods for re-routing.
778 #[inline(always)]
_set_method(&self, method: Method)779 pub(crate) fn _set_method(&self, method: Method) {
780 self.method.set(method);
781 }
782
783 /// Convert from Hyper types into a Rocket Request.
from_hyp( rocket: &'r Rocket, h_method: hyper::Method, h_headers: hyper::header::Headers, h_uri: hyper::RequestUri, h_addr: SocketAddr, ) -> Result<Request<'r>, String>784 pub(crate) fn from_hyp(
785 rocket: &'r Rocket,
786 h_method: hyper::Method,
787 h_headers: hyper::header::Headers,
788 h_uri: hyper::RequestUri,
789 h_addr: SocketAddr,
790 ) -> Result<Request<'r>, String> {
791 // Get a copy of the URI for later use.
792 let uri = match h_uri {
793 hyper::RequestUri::AbsolutePath(s) => s,
794 _ => return Err(format!("Bad URI: {}", h_uri)),
795 };
796
797 // Ensure that the method is known. TODO: Allow made-up methods?
798 let method = match Method::from_hyp(&h_method) {
799 Some(method) => method,
800 None => return Err(format!("Invalid method: {}", h_method))
801 };
802
803 // We need to re-parse the URI since we don't trust Hyper... :(
804 let uri = Origin::parse_owned(uri).map_err(|e| e.to_string())?;
805
806 // Construct the request object.
807 let mut request = Request::new(rocket, method, uri);
808 request.set_remote(h_addr);
809
810 // Set the request cookies, if they exist.
811 if let Some(cookie_headers) = h_headers.get_raw("Cookie") {
812 let mut cookie_jar = CookieJar::new();
813 for header in cookie_headers {
814 let raw_str = match std::str::from_utf8(header) {
815 Ok(string) => string,
816 Err(_) => continue
817 };
818
819 for cookie_str in raw_str.split(';').map(|s| s.trim()) {
820 if let Some(cookie) = Cookies::parse_cookie(cookie_str) {
821 cookie_jar.add_original(cookie);
822 }
823 }
824 }
825
826 request.state.cookies = RefCell::new(cookie_jar);
827 }
828
829 // Set the rest of the headers.
830 for hyp in h_headers.iter() {
831 if let Some(header_values) = h_headers.get_raw(hyp.name()) {
832 for value in header_values {
833 // This is not totally correct since values needn't be UTF8.
834 let value_str = String::from_utf8_lossy(value).into_owned();
835 let header = Header::new(hyp.name().to_string(), value_str);
836 request.add_header(header);
837 }
838 }
839 }
840
841 Ok(request)
842 }
843 }
844
845 impl fmt::Debug for Request<'_> {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result846 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
847 fmt.debug_struct("Request")
848 .field("method", &self.method)
849 .field("uri", &self.uri)
850 .field("headers", &self.headers())
851 .field("remote", &self.remote())
852 .finish()
853 }
854 }
855
856 impl fmt::Display for Request<'_> {
857 /// Pretty prints a Request. This is primarily used by Rocket's logging
858 /// infrastructure.
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result859 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
860 write!(f, "{} {}", Paint::green(self.method()), Paint::blue(&self.uri))?;
861
862 // Print the requests media type when the route specifies a format.
863 if let Some(media_type) = self.format() {
864 if !media_type.is_any() {
865 write!(f, " {}", Paint::yellow(media_type))?;
866 }
867 }
868
869 Ok(())
870 }
871 }
872
873 impl IndexedFormItem {
874 #[inline(always)]
from(s: &str, i: FormItem<'_>) -> Self875 fn from(s: &str, i: FormItem<'_>) -> Self {
876 let (r, k, v) = (indices(i.raw, s), indices(i.key, s), indices(i.value, s));
877 IndexedFormItem { raw: r, key: k, value: v }
878 }
879
880 #[inline(always)]
convert<'s>(&self, source: &'s str) -> FormItem<'s>881 fn convert<'s>(&self, source: &'s str) -> FormItem<'s> {
882 FormItem {
883 raw: source[self.raw.0..self.raw.1].into(),
884 key: source[self.key.0..self.key.1].into(),
885 value: source[self.value.0..self.value.1].into(),
886 }
887 }
888 }
889
indices(needle: &str, haystack: &str) -> (usize, usize)890 fn indices(needle: &str, haystack: &str) -> (usize, usize) {
891 Indexed::checked_from(needle, haystack)
892 .expect("segments inside of path/query")
893 .indices()
894 }
895