2016-08-26 08:55:11 +00:00
|
|
|
use std::cell::RefCell;
|
2017-01-13 15:50:51 +00:00
|
|
|
use std::net::SocketAddr;
|
2016-08-27 01:37:28 +00:00
|
|
|
use std::fmt;
|
2017-03-11 01:42:09 +00:00
|
|
|
use std::str;
|
2016-08-27 01:37:28 +00:00
|
|
|
|
|
|
|
use term_painter::Color::*;
|
|
|
|
use term_painter::ToStyle;
|
2016-08-26 08:55:11 +00:00
|
|
|
|
2017-04-13 09:36:51 +00:00
|
|
|
use state::{Container, Storage};
|
2017-01-21 03:31:46 +00:00
|
|
|
|
2016-03-15 03:43:52 +00:00
|
|
|
use error::Error;
|
2016-09-30 08:25:07 +00:00
|
|
|
use super::{FromParam, FromSegments};
|
2016-03-15 03:43:52 +00:00
|
|
|
|
2016-08-26 08:55:11 +00:00
|
|
|
use router::Route;
|
2016-12-21 08:09:22 +00:00
|
|
|
use http::uri::{URI, Segments};
|
2017-03-28 10:10:18 +00:00
|
|
|
use http::{Method, Header, HeaderMap, Cookies, Session, CookieJar, Key};
|
2017-03-31 07:18:58 +00:00
|
|
|
use http::{RawStr, ContentType, Accept, MediaType};
|
2016-12-16 00:34:19 +00:00
|
|
|
use http::hyper;
|
2016-08-26 08:55:11 +00:00
|
|
|
|
2017-03-28 10:10:18 +00:00
|
|
|
struct PresetState<'r> {
|
|
|
|
key: &'r Key,
|
|
|
|
managed_state: &'r Container,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct RequestState<'r> {
|
|
|
|
preset: Option<PresetState<'r>>,
|
|
|
|
params: RefCell<Vec<(usize, usize)>>,
|
|
|
|
cookies: RefCell<CookieJar>,
|
|
|
|
session: RefCell<CookieJar>,
|
2017-04-13 09:36:51 +00:00
|
|
|
accept: Storage<Option<Accept>>,
|
|
|
|
content_type: Storage<Option<ContentType>>,
|
2017-03-28 10:10:18 +00:00
|
|
|
}
|
|
|
|
|
2016-10-21 09:56:57 +00:00
|
|
|
/// The type of an incoming web request.
|
2016-10-01 03:22:06 +00:00
|
|
|
///
|
|
|
|
/// This should be used sparingly in Rocket applications. In particular, it
|
|
|
|
/// should likely only be used when writing
|
2017-02-04 00:56:29 +00:00
|
|
|
/// [FromRequest](/rocket/request/trait.FromRequest.html) implementations. It
|
2016-12-21 09:30:45 +00:00
|
|
|
/// contains all of the information for a given web request except for the body
|
|
|
|
/// data. This includes the HTTP method, URI, cookies, headers, and more.
|
2016-12-16 11:07:23 +00:00
|
|
|
pub struct Request<'r> {
|
|
|
|
method: Method,
|
2016-12-21 08:09:22 +00:00
|
|
|
uri: URI<'r>,
|
2016-12-16 11:07:23 +00:00
|
|
|
headers: HeaderMap<'r>,
|
2017-01-13 15:50:51 +00:00
|
|
|
remote: Option<SocketAddr>,
|
2017-03-28 10:10:18 +00:00
|
|
|
extra: RequestState<'r>
|
2016-03-22 05:04:39 +00:00
|
|
|
}
|
|
|
|
|
2016-12-16 11:07:23 +00:00
|
|
|
impl<'r> Request<'r> {
|
2016-12-21 09:30:45 +00:00
|
|
|
/// Create a new `Request` with the given `method` and `uri`. The `uri`
|
|
|
|
/// parameter can be of any type that implements `Into<URI>` including
|
|
|
|
/// `&str` and `String`; it must be a valid absolute URI.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use rocket::Request;
|
|
|
|
/// use rocket::http::Method;
|
|
|
|
///
|
2017-02-02 10:16:21 +00:00
|
|
|
/// # #[allow(unused_variables)]
|
2016-12-21 09:30:45 +00:00
|
|
|
/// let request = Request::new(Method::Get, "/uri");
|
|
|
|
/// ```
|
2017-03-28 10:10:18 +00:00
|
|
|
#[inline(always)]
|
2016-12-21 08:09:22 +00:00
|
|
|
pub fn new<U: Into<URI<'r>>>(method: Method, uri: U) -> Request<'r> {
|
2016-12-16 11:07:23 +00:00
|
|
|
Request {
|
|
|
|
method: method,
|
|
|
|
uri: uri.into(),
|
|
|
|
headers: HeaderMap::new(),
|
2017-01-13 15:50:51 +00:00
|
|
|
remote: None,
|
2017-03-28 10:10:18 +00:00
|
|
|
extra: RequestState {
|
|
|
|
preset: None,
|
|
|
|
params: RefCell::new(Vec::new()),
|
|
|
|
cookies: RefCell::new(CookieJar::new()),
|
|
|
|
session: RefCell::new(CookieJar::new()),
|
2017-04-13 09:36:51 +00:00
|
|
|
accept: Storage::new(),
|
|
|
|
content_type: Storage::new(),
|
2017-03-28 10:10:18 +00:00
|
|
|
}
|
2016-12-16 11:07:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-21 09:30:45 +00:00
|
|
|
/// Retrieve the method from `self`.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use rocket::Request;
|
|
|
|
/// use rocket::http::Method;
|
|
|
|
///
|
|
|
|
/// let request = Request::new(Method::Get, "/uri");
|
|
|
|
/// assert_eq!(request.method(), Method::Get);
|
|
|
|
/// ```
|
2016-12-16 11:07:23 +00:00
|
|
|
#[inline(always)]
|
|
|
|
pub fn method(&self) -> Method {
|
|
|
|
self.method
|
|
|
|
}
|
|
|
|
|
2016-12-21 09:30:45 +00:00
|
|
|
/// Set the method of `self`.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use rocket::Request;
|
|
|
|
/// use rocket::http::Method;
|
|
|
|
///
|
|
|
|
/// let mut request = Request::new(Method::Get, "/uri");
|
|
|
|
/// assert_eq!(request.method(), Method::Get);
|
|
|
|
///
|
|
|
|
/// request.set_method(Method::Post);
|
|
|
|
/// assert_eq!(request.method(), Method::Post);
|
|
|
|
/// ```
|
2016-12-16 11:07:23 +00:00
|
|
|
#[inline(always)]
|
|
|
|
pub fn set_method(&mut self, method: Method) {
|
|
|
|
self.method = method;
|
|
|
|
}
|
|
|
|
|
2016-12-21 09:30:45 +00:00
|
|
|
/// Borrow the URI from `self`, which must be an absolute URI.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use rocket::Request;
|
|
|
|
/// use rocket::http::Method;
|
|
|
|
///
|
2017-02-02 10:16:21 +00:00
|
|
|
/// let request = Request::new(Method::Get, "/uri");
|
2016-12-21 09:30:45 +00:00
|
|
|
/// assert_eq!(request.uri().as_str(), "/uri");
|
|
|
|
/// ```
|
2016-12-16 11:07:23 +00:00
|
|
|
#[inline(always)]
|
2016-12-21 08:09:22 +00:00
|
|
|
pub fn uri(&self) -> &URI {
|
|
|
|
&self.uri
|
2016-12-16 11:07:23 +00:00
|
|
|
}
|
|
|
|
|
2016-12-21 09:30:45 +00:00
|
|
|
/// Set the URI in `self`. The `uri` parameter can be of any type that
|
|
|
|
/// implements `Into<URI>` including `&str` and `String`; it must be a valid
|
|
|
|
/// absolute URI.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use rocket::Request;
|
|
|
|
/// use rocket::http::Method;
|
|
|
|
///
|
|
|
|
/// let mut request = Request::new(Method::Get, "/uri");
|
|
|
|
///
|
|
|
|
/// request.set_uri("/hello/Sergio?type=greeting");
|
|
|
|
/// assert_eq!(request.uri().as_str(), "/hello/Sergio?type=greeting");
|
|
|
|
/// ```
|
2016-12-16 11:07:23 +00:00
|
|
|
#[inline(always)]
|
2016-12-21 08:09:22 +00:00
|
|
|
pub fn set_uri<'u: 'r, U: Into<URI<'u>>>(&mut self, uri: U) {
|
2016-12-16 11:07:23 +00:00
|
|
|
self.uri = uri.into();
|
2017-03-28 10:10:18 +00:00
|
|
|
*self.extra.params.borrow_mut() = Vec::new();
|
2016-12-16 11:07:23 +00:00
|
|
|
}
|
|
|
|
|
2017-01-13 15:50:51 +00:00
|
|
|
/// Returns the address of the remote connection that initiated this
|
|
|
|
/// request if the address is known. If the address is not known, `None` is
|
|
|
|
/// returned.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use rocket::Request;
|
|
|
|
/// use rocket::http::Method;
|
|
|
|
///
|
|
|
|
/// let request = Request::new(Method::Get, "/uri");
|
|
|
|
/// assert!(request.remote().is_none());
|
|
|
|
/// ```
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn remote(&self) -> Option<SocketAddr> {
|
|
|
|
self.remote
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the remote address of `self` to `address`.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// Set the remote address to be 127.0.0.1:8000:
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use rocket::Request;
|
|
|
|
/// use rocket::http::Method;
|
|
|
|
/// use std::net::{SocketAddr, IpAddr, Ipv4Addr};
|
|
|
|
///
|
|
|
|
/// let mut request = Request::new(Method::Get, "/uri");
|
|
|
|
///
|
|
|
|
/// let (ip, port) = (IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8000);
|
|
|
|
/// let localhost = SocketAddr::new(ip, port);
|
|
|
|
/// request.set_remote(localhost);
|
|
|
|
///
|
|
|
|
/// assert_eq!(request.remote(), Some(localhost));
|
|
|
|
/// ```
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn set_remote(&mut self, address: SocketAddr) {
|
|
|
|
self.remote = Some(address);
|
|
|
|
}
|
|
|
|
|
2017-04-14 08:21:06 +00:00
|
|
|
/// Returns a [HeaderMap](/rocket/http/struct.HeaderMap.html) of all of the
|
|
|
|
/// headers in `self`.
|
2016-12-21 09:30:45 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use rocket::Request;
|
2017-02-02 10:16:21 +00:00
|
|
|
/// use rocket::http::Method;
|
2016-12-21 09:30:45 +00:00
|
|
|
///
|
2017-02-02 10:16:21 +00:00
|
|
|
/// let request = Request::new(Method::Get, "/uri");
|
2016-12-21 09:30:45 +00:00
|
|
|
/// let header_map = request.headers();
|
|
|
|
/// assert!(header_map.is_empty());
|
|
|
|
/// ```
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn headers(&self) -> &HeaderMap<'r> {
|
|
|
|
&self.headers
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Add the `header` to `self`'s headers.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use rocket::Request;
|
|
|
|
/// use rocket::http::{Method, ContentType};
|
|
|
|
///
|
|
|
|
/// let mut request = Request::new(Method::Get, "/uri");
|
|
|
|
/// assert!(request.headers().is_empty());
|
|
|
|
///
|
2017-02-01 11:12:24 +00:00
|
|
|
/// request.add_header(ContentType::HTML);
|
2016-12-21 09:30:45 +00:00
|
|
|
/// assert!(request.headers().contains("Content-Type"));
|
|
|
|
/// assert_eq!(request.headers().len(), 1);
|
|
|
|
/// ```
|
2016-12-16 11:07:23 +00:00
|
|
|
#[inline(always)]
|
2017-02-01 11:12:24 +00:00
|
|
|
pub fn add_header<H: Into<Header<'r>>>(&mut self, header: H) {
|
|
|
|
self.headers.add(header.into());
|
2016-12-16 11:07:23 +00:00
|
|
|
}
|
|
|
|
|
2016-12-21 09:30:45 +00:00
|
|
|
/// Replaces the value of the header with `header.name` with `header.value`.
|
|
|
|
/// If no such header existed, `header` is added.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use rocket::Request;
|
|
|
|
/// use rocket::http::{Method, ContentType};
|
|
|
|
///
|
|
|
|
/// let mut request = Request::new(Method::Get, "/uri");
|
|
|
|
/// assert!(request.headers().is_empty());
|
|
|
|
///
|
2017-04-13 09:36:51 +00:00
|
|
|
/// request.add_header(ContentType::Any);
|
|
|
|
/// assert_eq!(request.headers().get_one("Content-Type"), Some("*/*"));
|
2016-12-21 09:30:45 +00:00
|
|
|
///
|
2017-04-13 09:36:51 +00:00
|
|
|
/// request.replace_header(ContentType::PNG);
|
|
|
|
/// assert_eq!(request.headers().get_one("Content-Type"), Some("image/png"));
|
2016-12-21 09:30:45 +00:00
|
|
|
/// ```
|
2016-12-16 11:07:23 +00:00
|
|
|
#[inline(always)]
|
2017-02-01 11:12:24 +00:00
|
|
|
pub fn replace_header<H: Into<Header<'r>>>(&mut self, header: H) {
|
|
|
|
self.headers.replace(header.into());
|
2016-12-16 11:07:23 +00:00
|
|
|
}
|
|
|
|
|
2016-12-21 09:30:45 +00:00
|
|
|
/// Returns a borrow to the cookies in `self`.
|
|
|
|
///
|
2017-01-13 15:50:51 +00:00
|
|
|
/// Note that `Cookies` implements internal mutability, so this method
|
|
|
|
/// allows you to get _and_ set cookies in `self`.
|
2016-12-21 09:30:45 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// Add a new cookie to a request's cookies:
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use rocket::Request;
|
2017-02-02 10:16:21 +00:00
|
|
|
/// use rocket::http::{Cookie, Method};
|
2016-12-21 09:30:45 +00:00
|
|
|
///
|
2017-02-02 10:16:21 +00:00
|
|
|
/// let request = Request::new(Method::Get, "/uri");
|
2017-01-27 07:08:15 +00:00
|
|
|
/// request.cookies().add(Cookie::new("key", "val"));
|
|
|
|
/// request.cookies().add(Cookie::new("ans", format!("life: {}", 38 + 4)));
|
2016-12-21 09:30:45 +00:00
|
|
|
/// ```
|
2017-03-07 09:19:06 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn cookies(&self) -> Cookies {
|
2017-03-28 10:10:18 +00:00
|
|
|
match self.extra.cookies.try_borrow_mut() {
|
2017-03-08 11:28:12 +00:00
|
|
|
Ok(jar) => Cookies::new(jar),
|
2017-03-07 09:19:06 +00:00
|
|
|
Err(_) => {
|
|
|
|
error_!("Multiple `Cookies` instances are active at once.");
|
|
|
|
info_!("An instance of `Cookies` must be dropped before another \
|
|
|
|
can be retrieved.");
|
|
|
|
warn_!("The retrieved `Cookies` instance will be empty.");
|
|
|
|
Cookies::empty()
|
|
|
|
}
|
|
|
|
}
|
2016-12-16 11:07:23 +00:00
|
|
|
}
|
|
|
|
|
2017-03-08 11:28:12 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn session(&self) -> Session {
|
2017-03-28 10:10:18 +00:00
|
|
|
match self.extra.session.try_borrow_mut() {
|
|
|
|
Ok(jar) => Session::new(jar, self.preset().key),
|
2017-03-08 11:28:12 +00:00
|
|
|
Err(_) => {
|
|
|
|
error_!("Multiple `Session` instances are active at once.");
|
|
|
|
info_!("An instance of `Session` must be dropped before another \
|
|
|
|
can be retrieved.");
|
|
|
|
warn_!("The retrieved `Session` instance will be empty.");
|
2017-03-28 10:10:18 +00:00
|
|
|
Session::empty(self.preset().key)
|
2017-03-08 11:28:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Replace all of the cookies in `self` with those in `jar`.
|
2017-02-03 10:16:46 +00:00
|
|
|
#[inline]
|
2017-03-07 09:19:06 +00:00
|
|
|
pub(crate) fn set_cookies(&mut self, jar: CookieJar) {
|
2017-03-28 10:10:18 +00:00
|
|
|
self.extra.cookies = RefCell::new(jar);
|
2016-12-16 11:07:23 +00:00
|
|
|
}
|
|
|
|
|
2017-03-08 11:28:12 +00:00
|
|
|
/// Replace all of the session cookie in `self` with those in `jar`.
|
|
|
|
#[inline]
|
|
|
|
pub(crate) fn set_session(&mut self, jar: CookieJar) {
|
2017-03-28 10:10:18 +00:00
|
|
|
self.extra.session = RefCell::new(jar);
|
2017-03-08 11:28:12 +00:00
|
|
|
}
|
|
|
|
|
2017-04-14 21:35:22 +00:00
|
|
|
/// Returns the Content-Type header of `self`. If the header is not present,
|
|
|
|
/// returns `None`. The Content-Type header is cached after the first call
|
|
|
|
/// to this function. As a result, subsequent calls will always return the
|
|
|
|
/// same value.
|
2016-12-21 09:30:45 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use rocket::Request;
|
|
|
|
/// use rocket::http::{Method, ContentType};
|
|
|
|
///
|
|
|
|
/// let mut request = Request::new(Method::Get, "/uri");
|
2017-02-01 11:12:24 +00:00
|
|
|
/// assert_eq!(request.content_type(), None);
|
2017-04-13 09:36:51 +00:00
|
|
|
/// ```
|
2016-12-21 09:30:45 +00:00
|
|
|
///
|
2017-04-13 09:36:51 +00:00
|
|
|
/// ```rust
|
|
|
|
/// use rocket::Request;
|
|
|
|
/// use rocket::http::{Method, ContentType};
|
|
|
|
///
|
|
|
|
/// let mut request = Request::new(Method::Get, "/uri");
|
|
|
|
/// request.add_header(ContentType::JSON);
|
|
|
|
/// assert_eq!(request.content_type(), Some(&ContentType::JSON));
|
2016-12-21 09:30:45 +00:00
|
|
|
/// ```
|
2016-12-16 11:07:23 +00:00
|
|
|
#[inline(always)]
|
2017-04-13 09:36:51 +00:00
|
|
|
pub fn content_type(&self) -> Option<&ContentType> {
|
|
|
|
self.extra.content_type.get_or_set(|| {
|
|
|
|
self.headers().get_one("Content-Type").and_then(|v| v.parse().ok())
|
|
|
|
}).as_ref()
|
2017-03-28 10:10:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
2017-04-13 09:36:51 +00:00
|
|
|
pub fn accept(&self) -> Option<&Accept> {
|
|
|
|
self.extra.accept.get_or_set(|| {
|
|
|
|
self.headers().get_one("Accept").and_then(|v| v.parse().ok())
|
|
|
|
}).as_ref()
|
2017-03-28 10:10:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
2017-04-13 09:36:51 +00:00
|
|
|
pub fn accept_first(&self) -> Option<&MediaType> {
|
|
|
|
self.accept().and_then(|accept| accept.first()).map(|wmt| wmt.media_type())
|
2016-12-16 11:07:23 +00:00
|
|
|
}
|
|
|
|
|
2017-03-29 11:08:53 +00:00
|
|
|
#[inline(always)]
|
2017-04-13 09:36:51 +00:00
|
|
|
pub fn format(&self) -> Option<&MediaType> {
|
|
|
|
static ANY: MediaType = MediaType::Any;
|
2017-03-29 11:08:53 +00:00
|
|
|
if self.method.supports_payload() {
|
2017-04-13 09:36:51 +00:00
|
|
|
self.content_type().map(|ct| ct.media_type())
|
2017-03-29 11:08:53 +00:00
|
|
|
} else {
|
|
|
|
// FIXME: Should we be using `accept_first` or `preferred`? Or
|
|
|
|
// should we be checking neither and instead pass things through
|
|
|
|
// where the client accepts the thing at all?
|
|
|
|
self.accept()
|
2017-04-13 09:36:51 +00:00
|
|
|
.map(|accept| accept.preferred().media_type())
|
|
|
|
.or(Some(&ANY))
|
2017-03-29 11:08:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-31 05:51:23 +00:00
|
|
|
/// Retrieves and parses into `T` the 0-indexed `n`th dynamic parameter from
|
|
|
|
/// the request. Returns `Error::NoKey` if `n` is greater than the number of
|
2016-10-01 03:22:06 +00:00
|
|
|
/// params. Returns `Error::BadParse` if the parameter type `T` can't be
|
|
|
|
/// parsed from the parameter.
|
|
|
|
///
|
2016-12-21 09:30:45 +00:00
|
|
|
/// This method exists only to be used by manual routing. To retrieve
|
|
|
|
/// parameters from a request, use Rocket's code generation facilities.
|
|
|
|
///
|
2016-10-01 03:22:06 +00:00
|
|
|
/// # Example
|
|
|
|
///
|
2017-03-31 07:18:58 +00:00
|
|
|
/// Retrieve parameter `0`, which is expected to be a `String`, in a manual
|
2016-12-21 09:30:45 +00:00
|
|
|
/// route:
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use rocket::{Request, Data};
|
|
|
|
/// use rocket::handler::Outcome;
|
2016-10-01 03:22:06 +00:00
|
|
|
///
|
2017-02-02 10:16:21 +00:00
|
|
|
/// # #[allow(dead_code)]
|
2016-12-21 09:30:45 +00:00
|
|
|
/// fn name<'a>(req: &'a Request, _: Data) -> Outcome<'a> {
|
2017-03-31 07:18:58 +00:00
|
|
|
/// Outcome::of(req.get_param::<String>(0).unwrap_or("unnamed".into()))
|
2016-10-01 03:22:06 +00:00
|
|
|
/// }
|
|
|
|
/// ```
|
2016-12-16 11:07:23 +00:00
|
|
|
pub fn get_param<'a, T: FromParam<'a>>(&'a self, n: usize) -> Result<T, Error> {
|
2016-10-31 17:51:19 +00:00
|
|
|
let param = self.get_param_str(n).ok_or(Error::NoKey)?;
|
|
|
|
T::from_param(param).map_err(|_| Error::BadParse)
|
|
|
|
}
|
|
|
|
|
2016-12-21 09:30:45 +00:00
|
|
|
/// Set `self`'s parameters given that the route used to reach this request
|
|
|
|
/// was `route`. This should only be used internally by `Rocket` as improper
|
|
|
|
/// use may result in out of bounds indexing.
|
2017-01-13 15:50:51 +00:00
|
|
|
/// TODO: Figure out the mount path from here.
|
2017-02-03 10:16:46 +00:00
|
|
|
#[inline]
|
|
|
|
pub(crate) fn set_params(&self, route: &Route) {
|
2017-03-28 10:10:18 +00:00
|
|
|
*self.extra.params.borrow_mut() = route.get_param_indexes(self.uri());
|
2016-12-16 11:07:23 +00:00
|
|
|
}
|
|
|
|
|
2017-02-04 00:56:29 +00:00
|
|
|
/// Get the `n`th path parameter as a string, if it exists. This is used by
|
|
|
|
/// codegen.
|
2016-10-31 17:51:19 +00:00
|
|
|
#[doc(hidden)]
|
2017-03-31 07:18:58 +00:00
|
|
|
pub fn get_param_str(&self, n: usize) -> Option<&RawStr> {
|
2017-03-28 10:10:18 +00:00
|
|
|
let params = self.extra.params.borrow();
|
2016-10-07 03:57:17 +00:00
|
|
|
if n >= params.len() {
|
|
|
|
debug!("{} is >= param count {}", n, params.len());
|
2016-12-16 11:07:23 +00:00
|
|
|
return None;
|
2016-08-26 08:55:11 +00:00
|
|
|
}
|
|
|
|
|
2016-12-16 11:07:23 +00:00
|
|
|
let (i, j) = params[n];
|
2016-12-31 05:51:23 +00:00
|
|
|
let path = self.uri.path();
|
|
|
|
if j > path.len() {
|
2016-12-16 11:07:23 +00:00
|
|
|
error!("Couldn't retrieve parameter: internal count incorrect.");
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2017-03-31 07:18:58 +00:00
|
|
|
Some(path[i..j].into())
|
2016-09-12 01:57:04 +00:00
|
|
|
}
|
|
|
|
|
2016-10-01 03:22:06 +00:00
|
|
|
/// Retrieves and parses into `T` all of the path segments in the request
|
2016-12-31 05:51:23 +00:00
|
|
|
/// URI beginning at the 0-indexed `n`th dynamic parameter. `T` must
|
|
|
|
/// implement [FromSegments](/rocket/request/trait.FromSegments.html), which
|
|
|
|
/// is used to parse the segments.
|
|
|
|
///
|
|
|
|
/// This method exists only to be used by manual routing. To retrieve
|
|
|
|
/// segments from a request, use Rocket's code generation facilities.
|
2016-12-21 09:30:45 +00:00
|
|
|
///
|
|
|
|
/// # Error
|
|
|
|
///
|
2016-12-31 05:51:23 +00:00
|
|
|
/// If there are less than `n` segments, returns an `Err` of `NoKey`. If
|
2016-12-21 09:30:45 +00:00
|
|
|
/// parsing the segments failed, returns an `Err` of `BadParse`.
|
|
|
|
///
|
|
|
|
/// # Example
|
2016-10-01 03:22:06 +00:00
|
|
|
///
|
2016-12-31 05:51:23 +00:00
|
|
|
/// If the request URI is `"/hello/there/i/am/here"`, and the matched route
|
|
|
|
/// path for this request is `"/hello/<name>/i/<segs..>"`, then
|
2016-10-01 03:22:06 +00:00
|
|
|
/// `request.get_segments::<T>(1)` will attempt to parse the segments
|
2016-12-31 05:51:23 +00:00
|
|
|
/// `"am/here"` as type `T`.
|
|
|
|
pub fn get_segments<'a, T: FromSegments<'a>>(&'a self, n: usize)
|
2016-12-16 00:34:19 +00:00
|
|
|
-> Result<T, Error> {
|
2016-12-31 05:51:23 +00:00
|
|
|
let segments = self.get_raw_segments(n).ok_or(Error::NoKey)?;
|
2016-10-31 17:51:19 +00:00
|
|
|
T::from_segments(segments).map_err(|_| Error::BadParse)
|
|
|
|
}
|
|
|
|
|
2016-12-31 05:51:23 +00:00
|
|
|
/// Get the segments beginning at the `n`th dynamic parameter, if they
|
2017-02-04 00:56:29 +00:00
|
|
|
/// exist. Used by codegen.
|
2016-10-31 17:51:19 +00:00
|
|
|
#[doc(hidden)]
|
2016-12-31 05:51:23 +00:00
|
|
|
pub fn get_raw_segments(&self, n: usize) -> Option<Segments> {
|
2017-03-28 10:10:18 +00:00
|
|
|
let params = self.extra.params.borrow();
|
2016-12-31 05:51:23 +00:00
|
|
|
if n >= params.len() {
|
|
|
|
debug!("{} is >= param (segments) count {}", n, params.len());
|
|
|
|
return None;
|
2016-09-08 07:02:17 +00:00
|
|
|
}
|
2016-12-31 05:51:23 +00:00
|
|
|
|
|
|
|
let (i, j) = params[n];
|
|
|
|
let path = self.uri.path();
|
|
|
|
if j > path.len() {
|
|
|
|
error!("Couldn't retrieve segments: internal count incorrect.");
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(Segments(&path[i..j]))
|
2016-09-08 07:02:17 +00:00
|
|
|
}
|
|
|
|
|
2017-01-21 03:31:46 +00:00
|
|
|
/// Get the managed state container, if it exists. For internal use only!
|
2017-03-28 10:10:18 +00:00
|
|
|
#[inline(always)]
|
2017-03-29 11:08:53 +00:00
|
|
|
pub fn get_state<T: Send + Sync + 'static>(&self) -> Option<&'r T> {
|
2017-03-28 10:10:18 +00:00
|
|
|
self.preset().managed_state.try_get()
|
2017-01-21 03:31:46 +00:00
|
|
|
}
|
|
|
|
|
2017-03-28 10:10:18 +00:00
|
|
|
#[inline(always)]
|
|
|
|
fn preset(&self) -> &PresetState<'r> {
|
|
|
|
match self.extra.preset {
|
|
|
|
Some(ref state) => state,
|
|
|
|
None => {
|
|
|
|
error_!("Internal Rocket error: preset state is unset!");
|
|
|
|
panic!("Please report this error to the GitHub issue tracker.");
|
|
|
|
}
|
|
|
|
}
|
2017-01-21 03:31:46 +00:00
|
|
|
}
|
|
|
|
|
2017-03-28 10:10:18 +00:00
|
|
|
/// Set the precomputed state. For internal use only!
|
|
|
|
#[inline(always)]
|
|
|
|
pub(crate) fn set_preset_state(&mut self, key: &'r Key, state: &'r Container) {
|
|
|
|
self.extra.preset = Some(PresetState { key, managed_state: state });
|
2017-03-08 11:28:12 +00:00
|
|
|
}
|
|
|
|
|
2016-12-21 09:30:45 +00:00
|
|
|
/// Convert from Hyper types into a Rocket Request.
|
2017-02-03 10:16:46 +00:00
|
|
|
pub(crate) fn from_hyp(h_method: hyper::Method,
|
|
|
|
h_headers: hyper::header::Headers,
|
|
|
|
h_uri: hyper::RequestUri,
|
|
|
|
h_addr: SocketAddr,
|
|
|
|
) -> Result<Request<'r>, String> {
|
2016-12-16 11:07:23 +00:00
|
|
|
// Get a copy of the URI for later use.
|
2016-08-26 08:55:11 +00:00
|
|
|
let uri = match h_uri {
|
2016-12-21 08:09:22 +00:00
|
|
|
hyper::RequestUri::AbsolutePath(s) => s,
|
2016-09-30 22:20:11 +00:00
|
|
|
_ => return Err(format!("Bad URI: {}", h_uri)),
|
2016-08-27 01:37:28 +00:00
|
|
|
};
|
|
|
|
|
2016-12-16 11:07:23 +00:00
|
|
|
// Ensure that the method is known. TODO: Allow made-up methods?
|
2016-08-27 01:37:28 +00:00
|
|
|
let method = match Method::from_hyp(&h_method) {
|
2016-10-09 04:37:28 +00:00
|
|
|
Some(method) => method,
|
2016-12-16 11:07:23 +00:00
|
|
|
None => return Err(format!("Invalid method: {}", h_method))
|
2016-08-26 08:55:11 +00:00
|
|
|
};
|
|
|
|
|
2016-12-16 11:07:23 +00:00
|
|
|
// Construct the request object.
|
|
|
|
let mut request = Request::new(method, uri);
|
2017-03-28 10:10:18 +00:00
|
|
|
request.set_remote(h_addr);
|
2016-09-12 01:57:04 +00:00
|
|
|
|
2017-03-08 11:28:12 +00:00
|
|
|
// Set the request cookies, if they exist.
|
2017-01-27 07:08:15 +00:00
|
|
|
if let Some(cookie_headers) = h_headers.get_raw("Cookie") {
|
2017-03-08 11:28:12 +00:00
|
|
|
let mut cookie_jar = CookieJar::new();
|
|
|
|
let mut session_jar = CookieJar::new();
|
2017-01-27 07:08:15 +00:00
|
|
|
for header in cookie_headers {
|
|
|
|
let raw_str = match ::std::str::from_utf8(header) {
|
|
|
|
Ok(string) => string,
|
|
|
|
Err(_) => continue
|
|
|
|
};
|
|
|
|
|
2017-03-08 11:28:12 +00:00
|
|
|
for cookie_str in raw_str.split(";").map(|s| s.trim()) {
|
|
|
|
if let Some(cookie) = Session::parse_cookie(cookie_str) {
|
|
|
|
session_jar.add_original(cookie);
|
|
|
|
} else if let Some(cookie) = Cookies::parse_cookie(cookie_str) {
|
|
|
|
cookie_jar.add_original(cookie);
|
|
|
|
}
|
2017-01-27 07:08:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-08 11:28:12 +00:00
|
|
|
request.set_cookies(cookie_jar);
|
|
|
|
request.set_session(session_jar);
|
2016-12-16 00:34:19 +00:00
|
|
|
}
|
|
|
|
|
2016-12-16 11:07:23 +00:00
|
|
|
// Set the rest of the headers.
|
|
|
|
for hyp in h_headers.iter() {
|
2017-03-11 01:42:09 +00:00
|
|
|
if let Some(header_values) = h_headers.get_raw(hyp.name()) {
|
|
|
|
for value in header_values {
|
2017-03-16 02:20:20 +00:00
|
|
|
// This is not totally correct since values needn't be UTF8.
|
|
|
|
let value_str = String::from_utf8_lossy(value).into_owned();
|
|
|
|
let header = Header::new(hyp.name().to_string(), value_str);
|
2017-03-11 01:42:09 +00:00
|
|
|
request.add_header(header);
|
|
|
|
}
|
|
|
|
}
|
2016-12-16 11:07:23 +00:00
|
|
|
}
|
2016-08-27 01:37:28 +00:00
|
|
|
|
|
|
|
Ok(request)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-16 11:07:23 +00:00
|
|
|
impl<'r> fmt::Display for Request<'r> {
|
2016-10-01 03:22:06 +00:00
|
|
|
/// Pretty prints a Request. This is primarily used by Rocket's logging
|
|
|
|
/// infrastructure.
|
2016-08-27 01:37:28 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2016-10-13 02:08:19 +00:00
|
|
|
write!(f, "{} {}", Green.paint(&self.method), Blue.paint(&self.uri))?;
|
2017-02-01 11:12:24 +00:00
|
|
|
if let Some(content_type) = self.content_type() {
|
|
|
|
if self.method.supports_payload() {
|
|
|
|
write!(f, " {}", Yellow.paint(content_type))?;
|
|
|
|
}
|
2016-10-13 02:08:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
2016-03-15 03:43:52 +00:00
|
|
|
}
|
|
|
|
}
|