2017-01-13 21:25:33 +00:00
|
|
|
use std::str::FromStr;
|
2016-03-17 08:57:04 +00:00
|
|
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, SocketAddr};
|
2016-09-08 07:02:17 +00:00
|
|
|
use std::path::PathBuf;
|
2016-10-31 17:31:39 +00:00
|
|
|
use std::fmt::Debug;
|
|
|
|
|
2017-01-13 21:25:33 +00:00
|
|
|
use http::uri::{URI, Segments, SegmentError};
|
2017-03-31 07:18:58 +00:00
|
|
|
use http::RawStr;
|
2016-10-04 00:25:27 +00:00
|
|
|
|
2016-10-21 09:56:57 +00:00
|
|
|
/// Trait to convert a dynamic path segment string to a concrete value.
|
|
|
|
///
|
|
|
|
/// This trait is used by Rocket's code generation facilities to parse dynamic
|
|
|
|
/// path segment string values into a given type. That is, when a path contains
|
2016-12-10 10:55:25 +00:00
|
|
|
/// a dynamic segment `<param>` where `param` has some type `T` that implements
|
|
|
|
/// `FromParam`, `T::from_param` will be called.
|
2016-10-21 09:56:57 +00:00
|
|
|
///
|
|
|
|
/// # Forwarding
|
|
|
|
///
|
|
|
|
/// If the conversion fails, the incoming request will be forwarded to the next
|
|
|
|
/// matching route, if any. For instance, consider the following route and
|
|
|
|
/// handler for the dynamic `"/<id>"` path:
|
|
|
|
///
|
|
|
|
/// ```rust
|
2017-08-29 03:14:59 +00:00
|
|
|
/// # #![feature(plugin, decl_macro)]
|
2016-10-24 08:09:50 +00:00
|
|
|
/// # #![plugin(rocket_codegen)]
|
|
|
|
/// # extern crate rocket;
|
2016-10-21 09:56:57 +00:00
|
|
|
/// #[get("/<id>")]
|
|
|
|
/// fn hello(id: usize) -> String {
|
2017-02-02 10:16:21 +00:00
|
|
|
/// # let _id = id;
|
2016-10-21 09:56:57 +00:00
|
|
|
/// # /*
|
|
|
|
/// ...
|
|
|
|
/// # */
|
|
|
|
/// # "".to_string()
|
|
|
|
/// }
|
|
|
|
/// # fn main() { }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// If `usize::from_param` returns an `Ok(usize)` variant, the encapsulated
|
|
|
|
/// value is used as the `id` function parameter. If not, the request is
|
|
|
|
/// forwarded to the next matching route. Since there are no additional matching
|
|
|
|
/// routes, this example will result in a 404 error for requests with invalid
|
|
|
|
/// `id` values.
|
|
|
|
///
|
2016-10-24 08:09:50 +00:00
|
|
|
/// # Catching Errors
|
|
|
|
///
|
2016-12-10 10:55:25 +00:00
|
|
|
/// Sometimes, a forward is not desired, and instead, we simply want to know
|
|
|
|
/// that the dynamic path segment could not be parsed into some desired type
|
|
|
|
/// `T`. In these cases, types of `Option<T>` or `Result<T, T::Error>` can be
|
2017-01-15 10:05:17 +00:00
|
|
|
/// used. These types implement `FromParam` themselves. Their implementations
|
2016-12-10 10:55:25 +00:00
|
|
|
/// always return successfully, so they never forward. They can be used to
|
|
|
|
/// determine if the `FromParam` call failed and to retrieve the error value
|
|
|
|
/// from the failed `from_param` call.
|
|
|
|
///
|
|
|
|
/// For instance, imagine you've asked for an `<id>` as a `usize`. To determine
|
|
|
|
/// when the `<id>` was not a valid `usize` and retrieve the string that failed
|
2017-03-31 07:18:58 +00:00
|
|
|
/// to parse, you can use a `Result<usize, &RawStr>` type for the `<id>`
|
|
|
|
/// parameter as follows:
|
2016-12-10 10:55:25 +00:00
|
|
|
///
|
|
|
|
/// ```rust
|
2017-08-29 03:14:59 +00:00
|
|
|
/// # #![feature(plugin, decl_macro)]
|
2016-12-10 10:55:25 +00:00
|
|
|
/// # #![plugin(rocket_codegen)]
|
|
|
|
/// # extern crate rocket;
|
2017-03-31 07:18:58 +00:00
|
|
|
/// # use rocket::http::RawStr;
|
2016-12-10 10:55:25 +00:00
|
|
|
/// #[get("/<id>")]
|
2017-03-31 07:18:58 +00:00
|
|
|
/// fn hello(id: Result<usize, &RawStr>) -> String {
|
2016-12-10 10:55:25 +00:00
|
|
|
/// match id {
|
|
|
|
/// Ok(id_num) => format!("usize: {}", id_num),
|
|
|
|
/// Err(string) => format!("Not a usize: {}", string)
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// # fn main() { }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// # Provided Implementations
|
|
|
|
///
|
|
|
|
/// Rocket implements `FromParam` for several standard library types. Their
|
|
|
|
/// behavior is documented here.
|
|
|
|
///
|
2017-08-14 16:49:09 +00:00
|
|
|
/// * **f32, f64, isize, i8, i16, i32, i64, usize, u8, u16, u32, u64, bool,
|
2017-03-30 02:05:49 +00:00
|
|
|
/// IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, SocketAddr**
|
2016-12-10 10:55:25 +00:00
|
|
|
///
|
2017-03-30 04:06:15 +00:00
|
|
|
/// A value is parsed successfully if the `from_str` method from the given
|
2016-12-10 10:55:25 +00:00
|
|
|
/// type returns successfully. Otherwise, the raw path segment is returned
|
|
|
|
/// in the `Err` value.
|
|
|
|
///
|
2017-06-22 11:29:59 +00:00
|
|
|
/// * **&[`RawStr`](/rocket/http/struct.RawStr.html)**
|
2016-12-10 10:55:25 +00:00
|
|
|
///
|
|
|
|
/// _This implementation always returns successfully._
|
|
|
|
///
|
|
|
|
/// The path segment is passed directly with no modification.
|
|
|
|
///
|
|
|
|
/// * **String**
|
|
|
|
///
|
|
|
|
/// Percent decodes the path segment. If the decode is successful, the
|
|
|
|
/// decoded string is returned. Otherwise, an `Err` with the original path
|
|
|
|
/// segment is returned.
|
|
|
|
///
|
2016-12-11 01:41:44 +00:00
|
|
|
/// * **Option<T>** _where_ **T: FromParam**
|
2016-12-10 10:55:25 +00:00
|
|
|
///
|
|
|
|
/// _This implementation always returns successfully._
|
|
|
|
///
|
|
|
|
/// The path segment is parsed by `T`'s `FromParam` implementation. If the
|
|
|
|
/// parse succeeds, a `Some(parsed_value)` is returned. Otherwise, a `None`
|
|
|
|
/// is returned.
|
|
|
|
///
|
2016-12-11 01:41:44 +00:00
|
|
|
/// * **Result<T, T::Error>** _where_ **T: FromParam**
|
2016-12-10 10:55:25 +00:00
|
|
|
///
|
|
|
|
/// _This implementation always returns successfully._
|
|
|
|
///
|
|
|
|
/// The path segment is parsed by `T`'s `FromParam` implementation. The
|
|
|
|
/// returned `Result` value is returned.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// Say you want to parse a segment of the form:
|
|
|
|
///
|
|
|
|
/// ```ignore
|
|
|
|
/// [a-zA-Z]+:[0-9]+
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// into the following structure, where the string before the `:` is stored in
|
|
|
|
/// `key` and the number after the colon is stored in `value`:
|
|
|
|
///
|
|
|
|
/// ```rust
|
2017-02-02 10:16:21 +00:00
|
|
|
/// # #[allow(dead_code)]
|
2016-12-10 10:55:25 +00:00
|
|
|
/// struct MyParam<'r> {
|
|
|
|
/// key: &'r str,
|
|
|
|
/// value: usize
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// The following implementation accomplishes this:
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use rocket::request::FromParam;
|
2017-03-31 07:18:58 +00:00
|
|
|
/// use rocket::http::RawStr;
|
2017-02-02 10:16:21 +00:00
|
|
|
/// # #[allow(dead_code)]
|
2016-12-10 10:55:25 +00:00
|
|
|
/// # struct MyParam<'r> { key: &'r str, value: usize }
|
|
|
|
///
|
|
|
|
/// impl<'r> FromParam<'r> for MyParam<'r> {
|
2017-03-31 07:18:58 +00:00
|
|
|
/// type Error = &'r RawStr;
|
2016-12-10 10:55:25 +00:00
|
|
|
///
|
2017-03-31 07:18:58 +00:00
|
|
|
/// fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
|
2016-12-10 10:55:25 +00:00
|
|
|
/// let (key, val_str) = match param.find(':') {
|
|
|
|
/// Some(i) if i > 0 => (¶m[..i], ¶m[(i + 1)..]),
|
|
|
|
/// _ => return Err(param)
|
|
|
|
/// };
|
|
|
|
///
|
|
|
|
/// if !key.chars().all(|c| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
|
|
|
|
/// return Err(param);
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// val_str.parse().map(|value| {
|
|
|
|
/// MyParam {
|
|
|
|
/// key: key,
|
|
|
|
/// value: value
|
|
|
|
/// }
|
|
|
|
/// }).map_err(|_| param)
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// With the implementation, the `MyParam` type can be used as the target of a
|
|
|
|
/// dynamic path segment:
|
|
|
|
///
|
|
|
|
/// ```rust
|
2017-08-29 03:14:59 +00:00
|
|
|
/// # #![feature(plugin, decl_macro)]
|
2016-12-10 10:55:25 +00:00
|
|
|
/// # #![plugin(rocket_codegen)]
|
|
|
|
/// # extern crate rocket;
|
|
|
|
/// # use rocket::request::FromParam;
|
2017-03-31 07:18:58 +00:00
|
|
|
/// # use rocket::http::RawStr;
|
2017-02-02 10:16:21 +00:00
|
|
|
/// # #[allow(dead_code)]
|
2016-12-10 10:55:25 +00:00
|
|
|
/// # struct MyParam<'r> { key: &'r str, value: usize }
|
|
|
|
/// # impl<'r> FromParam<'r> for MyParam<'r> {
|
2017-03-31 07:18:58 +00:00
|
|
|
/// # type Error = &'r RawStr;
|
|
|
|
/// # fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
|
2016-12-10 10:55:25 +00:00
|
|
|
/// # Err(param)
|
|
|
|
/// # }
|
|
|
|
/// # }
|
|
|
|
/// #
|
|
|
|
/// #[get("/<key_val>")]
|
|
|
|
/// fn hello(key_val: MyParam) -> String {
|
2017-02-02 10:16:21 +00:00
|
|
|
/// # let _kv = key_val;
|
2016-12-10 10:55:25 +00:00
|
|
|
/// # /*
|
|
|
|
/// ...
|
|
|
|
/// # */
|
|
|
|
/// # "".to_string()
|
|
|
|
/// }
|
|
|
|
/// # fn main() { }
|
|
|
|
/// ```
|
2016-03-17 08:57:04 +00:00
|
|
|
pub trait FromParam<'a>: Sized {
|
2016-10-21 09:56:57 +00:00
|
|
|
/// The associated error to be returned when parsing fails.
|
2016-10-31 17:31:39 +00:00
|
|
|
type Error: Debug;
|
2016-10-21 09:56:57 +00:00
|
|
|
|
|
|
|
/// Parses an instance of `Self` from a dynamic path parameter string or
|
|
|
|
/// returns an `Error` if one cannot be parsed.
|
2017-03-31 07:18:58 +00:00
|
|
|
fn from_param(param: &'a RawStr) -> Result<Self, Self::Error>;
|
2016-03-17 08:57:04 +00:00
|
|
|
}
|
|
|
|
|
2017-03-31 07:18:58 +00:00
|
|
|
impl<'a> FromParam<'a> for &'a RawStr {
|
2016-09-30 08:25:07 +00:00
|
|
|
type Error = ();
|
2017-03-31 07:18:58 +00:00
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
fn from_param(param: &'a RawStr) -> Result<&'a RawStr, Self::Error> {
|
2016-03-17 08:57:04 +00:00
|
|
|
Ok(param)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-27 01:37:28 +00:00
|
|
|
impl<'a> FromParam<'a> for String {
|
2017-03-31 07:18:58 +00:00
|
|
|
type Error = &'a RawStr;
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
fn from_param(param: &'a RawStr) -> Result<String, Self::Error> {
|
|
|
|
param.percent_decode().map(|cow| cow.into_owned()).map_err(|_| param)
|
2016-08-27 01:37:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-17 08:57:04 +00:00
|
|
|
macro_rules! impl_with_fromstr {
|
2016-04-04 11:19:07 +00:00
|
|
|
($($T:ident),+) => ($(
|
|
|
|
impl<'a> FromParam<'a> for $T {
|
2017-03-31 07:18:58 +00:00
|
|
|
type Error = &'a RawStr;
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
fn from_param(param: &'a RawStr) -> Result<Self, Self::Error> {
|
|
|
|
$T::from_str(param.as_str()).map_err(|_| param)
|
2016-03-17 08:57:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)+)
|
|
|
|
}
|
|
|
|
|
|
|
|
impl_with_fromstr!(f32, f64, isize, i8, i16, i32, i64, usize, u8, u16, u32, u64,
|
2016-08-27 01:37:28 +00:00
|
|
|
bool, IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6,
|
2016-03-17 08:57:04 +00:00
|
|
|
SocketAddr);
|
2016-09-08 07:02:17 +00:00
|
|
|
|
2016-10-31 17:31:39 +00:00
|
|
|
impl<'a, T: FromParam<'a>> FromParam<'a> for Result<T, T::Error> {
|
2017-03-31 07:18:58 +00:00
|
|
|
type Error = !;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn from_param(param: &'a RawStr) -> Result<Self, Self::Error> {
|
|
|
|
match T::from_param(param) {
|
|
|
|
Ok(val) => Ok(Ok(val)),
|
|
|
|
Err(e) => Ok(Err(e)),
|
|
|
|
}
|
2016-10-31 17:31:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T: FromParam<'a>> FromParam<'a> for Option<T> {
|
2017-03-31 07:18:58 +00:00
|
|
|
type Error = !;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn from_param(param: &'a RawStr) -> Result<Self, Self::Error> {
|
|
|
|
match T::from_param(param) {
|
|
|
|
Ok(val) => Ok(Some(val)),
|
|
|
|
Err(_) => Ok(None)
|
|
|
|
}
|
2016-10-31 17:31:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-21 09:56:57 +00:00
|
|
|
/// Trait to convert _many_ dynamic path segment strings to a concrete value.
|
|
|
|
///
|
|
|
|
/// This is the `..` analog to [FromParam](trait.FromParam.html), and its
|
|
|
|
/// functionality is identical to it with one exception: this trait applies to
|
|
|
|
/// segment parameters of the form `<param..>`, where `param` is of some type
|
|
|
|
/// `T` that implements `FromSegments`. `T::from_segments` is called to convert
|
|
|
|
/// the matched segments (via the
|
|
|
|
/// [Segments](/rocket/http/uri/struct.Segments.html) iterator) into the
|
|
|
|
/// implementing type.
|
2016-12-23 10:39:34 +00:00
|
|
|
///
|
|
|
|
/// # Provided Implementations
|
|
|
|
///
|
|
|
|
/// Rocket implements `FromParam` for `PathBuf`. The `PathBuf` implementation
|
|
|
|
/// constructs a path from the segments iterator. Each segment is
|
|
|
|
/// percent-decoded. If a segment equals ".." before or after decoding, the
|
|
|
|
/// previous segment (if any) is omitted. For security purposes, any other
|
|
|
|
/// segments that begin with "*" or "." are ignored. If a percent-decoded
|
|
|
|
/// segment results in invalid UTF8, an `Err` is returned with the `Utf8Error`.
|
2016-09-08 07:02:17 +00:00
|
|
|
pub trait FromSegments<'a>: Sized {
|
2016-10-21 09:56:57 +00:00
|
|
|
/// The associated error to be returned when parsing fails.
|
2016-10-31 17:31:39 +00:00
|
|
|
type Error: Debug;
|
2016-10-21 09:56:57 +00:00
|
|
|
|
|
|
|
/// Parses an instance of `Self` from many dynamic path parameter strings or
|
|
|
|
/// returns an `Error` if one cannot be parsed.
|
2016-09-30 08:25:07 +00:00
|
|
|
fn from_segments(segments: Segments<'a>) -> Result<Self, Self::Error>;
|
2016-09-08 07:02:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> FromSegments<'a> for Segments<'a> {
|
2017-03-31 07:18:58 +00:00
|
|
|
type Error = !;
|
2017-01-13 21:25:33 +00:00
|
|
|
|
2017-03-31 07:18:58 +00:00
|
|
|
#[inline(always)]
|
|
|
|
fn from_segments(segments: Segments<'a>) -> Result<Segments<'a>, Self::Error> {
|
2016-09-08 07:02:17 +00:00
|
|
|
Ok(segments)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-02 15:55:56 +00:00
|
|
|
/// Creates a `PathBuf` from a `Segments` iterator. The returned `PathBuf` is
|
|
|
|
/// percent-decoded. If a segment is equal to "..", the previous segment (if
|
2017-01-13 21:25:33 +00:00
|
|
|
/// any) is skipped.
|
|
|
|
///
|
|
|
|
/// For security purposes, if a segment meets any of the following conditions,
|
|
|
|
/// an `Err` is returned indicating the condition met:
|
|
|
|
///
|
2017-03-31 01:15:36 +00:00
|
|
|
/// * Decoded segment starts with any of: `.` (except `..`), `*`
|
2017-01-13 21:25:33 +00:00
|
|
|
/// * Decoded segment ends with any of: `:`, `>`, `<`
|
|
|
|
/// * Decoded segment contains any of: `/`
|
|
|
|
/// * On Windows, decoded segment contains any of: '\'
|
|
|
|
/// * Percent-encoding results in invalid UTF8.
|
|
|
|
///
|
|
|
|
/// As a result of these conditions, a `PathBuf` derived via `FromSegments` is
|
|
|
|
/// safe to interpolate within, or use as a suffix of, a path without additional
|
|
|
|
/// checks.
|
2016-09-08 07:02:17 +00:00
|
|
|
impl<'a> FromSegments<'a> for PathBuf {
|
2017-01-13 21:25:33 +00:00
|
|
|
type Error = SegmentError;
|
2016-11-02 15:55:56 +00:00
|
|
|
|
2017-01-13 21:25:33 +00:00
|
|
|
fn from_segments(segments: Segments<'a>) -> Result<PathBuf, SegmentError> {
|
2016-11-02 15:55:56 +00:00
|
|
|
let mut buf = PathBuf::new();
|
|
|
|
for segment in segments {
|
2017-01-13 21:25:33 +00:00
|
|
|
let decoded = URI::percent_decode(segment.as_bytes())
|
|
|
|
.map_err(|e| SegmentError::Utf8(e))?;
|
|
|
|
|
2016-11-02 15:55:56 +00:00
|
|
|
if decoded == ".." {
|
|
|
|
buf.pop();
|
2017-01-13 21:25:33 +00:00
|
|
|
} else if decoded.starts_with('.') {
|
|
|
|
return Err(SegmentError::BadStart('.'))
|
|
|
|
} else if decoded.starts_with('*') {
|
|
|
|
return Err(SegmentError::BadStart('*'))
|
|
|
|
} else if decoded.ends_with(':') {
|
|
|
|
return Err(SegmentError::BadEnd(':'))
|
|
|
|
} else if decoded.ends_with('>') {
|
|
|
|
return Err(SegmentError::BadEnd('>'))
|
|
|
|
} else if decoded.ends_with('<') {
|
|
|
|
return Err(SegmentError::BadEnd('<'))
|
|
|
|
} else if decoded.contains('/') {
|
|
|
|
return Err(SegmentError::BadChar('/'))
|
|
|
|
} else if cfg!(windows) && decoded.contains('\\') {
|
|
|
|
return Err(SegmentError::BadChar('\\'))
|
|
|
|
} else {
|
2016-11-02 15:55:56 +00:00
|
|
|
buf.push(&*decoded)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(buf)
|
2016-09-08 07:02:17 +00:00
|
|
|
}
|
|
|
|
}
|
2016-10-31 17:31:39 +00:00
|
|
|
|
|
|
|
impl<'a, T: FromSegments<'a>> FromSegments<'a> for Result<T, T::Error> {
|
2017-03-31 07:18:58 +00:00
|
|
|
type Error = !;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn from_segments(segments: Segments<'a>) -> Result<Result<T, T::Error>, !> {
|
|
|
|
match T::from_segments(segments) {
|
|
|
|
Ok(val) => Ok(Ok(val)),
|
|
|
|
Err(e) => Ok(Err(e)),
|
|
|
|
}
|
2016-10-31 17:31:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T: FromSegments<'a>> FromSegments<'a> for Option<T> {
|
2017-03-31 07:18:58 +00:00
|
|
|
type Error = !;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn from_segments(segments: Segments<'a>) -> Result<Option<T>, !> {
|
|
|
|
match T::from_segments(segments) {
|
|
|
|
Ok(val) => Ok(Some(val)),
|
|
|
|
Err(_) => Ok(None)
|
|
|
|
}
|
2016-10-31 17:31:39 +00:00
|
|
|
}
|
|
|
|
}
|