2016-11-02 15:55:56 +00:00
|
|
|
use std::str::{Utf8Error, 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;
|
|
|
|
|
2016-11-02 15:55:56 +00:00
|
|
|
use http::uri::{URI, Segments};
|
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
|
|
|
|
/// a dynamic segment `<param>` where `param` has some type `T` that
|
|
|
|
/// implements `FromParam`, `T::from_param` will be called.
|
|
|
|
///
|
|
|
|
/// # 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
|
2016-10-24 08:09:50 +00:00
|
|
|
/// # #![feature(plugin)]
|
|
|
|
/// # #![plugin(rocket_codegen)]
|
|
|
|
/// # extern crate rocket;
|
2016-10-21 09:56:57 +00:00
|
|
|
/// #[get("/<id>")]
|
|
|
|
/// fn hello(id: usize) -> String {
|
|
|
|
/// # /*
|
|
|
|
/// ...
|
|
|
|
/// # */
|
|
|
|
/// # "".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-10-21 09:56:57 +00:00
|
|
|
/// # `str` vs. `String`
|
|
|
|
///
|
|
|
|
/// Paths are URL encoded. As a result, the `str` `FromParam` implementation
|
|
|
|
/// returns the raw, URL encoded version of the path segment string. On the
|
|
|
|
/// other hand, `String` decodes the path parameter, but requires an allocation
|
|
|
|
/// to do so. This tradeoff is similiar to that of form values, and you should
|
|
|
|
/// use whichever makes sense for your application.
|
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.
|
2016-09-30 08:25:07 +00:00
|
|
|
fn from_param(param: &'a str) -> Result<Self, Self::Error>;
|
2016-03-17 08:57:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> FromParam<'a> for &'a str {
|
2016-09-30 08:25:07 +00:00
|
|
|
type Error = ();
|
|
|
|
fn from_param(param: &'a str) -> Result<&'a str, 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 {
|
2016-09-30 08:25:07 +00:00
|
|
|
type Error = &'a str;
|
|
|
|
fn from_param(p: &'a str) -> Result<String, Self::Error> {
|
2016-11-02 15:55:56 +00:00
|
|
|
URI::percent_decode(p.as_bytes()).map_err(|_| p).map(|s| s.into_owned())
|
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 {
|
2016-09-30 08:25:07 +00:00
|
|
|
type Error = &'a str;
|
|
|
|
fn from_param(param: &'a str) -> Result<Self, Self::Error> {
|
|
|
|
$T::from_str(param).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> {
|
|
|
|
type Error = ();
|
|
|
|
fn from_param(p: &'a str) -> Result<Self, Self::Error> {
|
|
|
|
Ok(match T::from_param(p) {
|
|
|
|
Ok(val) => Ok(val),
|
|
|
|
Err(e) => Err(e),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T: FromParam<'a>> FromParam<'a> for Option<T> {
|
|
|
|
type Error = ();
|
|
|
|
fn from_param(p: &'a str) -> Result<Self, Self::Error> {
|
|
|
|
Ok(match T::from_param(p) {
|
|
|
|
Ok(val) => Some(val),
|
|
|
|
Err(_) => None
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-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> {
|
2016-09-30 08:25:07 +00:00
|
|
|
type Error = ();
|
|
|
|
fn from_segments(segments: Segments<'a>) -> Result<Segments<'a>, ()> {
|
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
|
|
|
|
/// any) is skipped. 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.
|
2016-09-08 07:02:17 +00:00
|
|
|
impl<'a> FromSegments<'a> for PathBuf {
|
2016-11-02 15:55:56 +00:00
|
|
|
type Error = Utf8Error;
|
|
|
|
|
|
|
|
fn from_segments(segments: Segments<'a>) -> Result<PathBuf, Utf8Error> {
|
|
|
|
let mut buf = PathBuf::new();
|
|
|
|
for segment in segments {
|
|
|
|
let decoded = URI::percent_decode(segment.as_bytes())?;
|
|
|
|
if decoded == ".." {
|
|
|
|
buf.pop();
|
|
|
|
} else if !(decoded.starts_with(".") || decoded.starts_with("*")) {
|
|
|
|
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> {
|
|
|
|
type Error = ();
|
|
|
|
fn from_segments(segments: Segments<'a>) -> Result<Result<T, T::Error>, ()> {
|
|
|
|
Ok(match T::from_segments(segments) {
|
|
|
|
Ok(val) => Ok(val),
|
|
|
|
Err(e) => Err(e),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T: FromSegments<'a>> FromSegments<'a> for Option<T> {
|
|
|
|
type Error = ();
|
|
|
|
fn from_segments(segments: Segments<'a>) -> Result<Option<T>, ()> {
|
|
|
|
Ok(match T::from_segments(segments) {
|
|
|
|
Ok(val) => Some(val),
|
|
|
|
Err(_) => None
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|