Rocket/core/lib/src/router/route.rs

366 lines
12 KiB
Rust
Raw Normal View History

use std::fmt::{self, Display};
use std::convert::From;
use yansi::Color::*;
use codegen::StaticRouteInfo;
use handler::Handler;
use http::{Method, MediaType};
use http::route::{RouteSegment, Kind, Error as SegmentError};
Overhaul URI types. This is fairly large commit with several entangled logical changes. The primary change in this commit is to completely overhaul how URI handling in Rocket works. Prior to this commit, the `Uri` type acted as an origin API. Its parser was minimal and lenient, allowing URIs that were invalid according to RFC 7230. By contrast, the new `Uri` type brings with it a strict RFC 7230 compliant parser. The `Uri` type now represents any kind of valid URI, not simply `Origin` types. Three new URI types were introduced: * `Origin` - represents valid origin URIs * `Absolute` - represents valid absolute URIs * `Authority` - represents valid authority URIs The `Origin` type replaces `Uri` in many cases: * As fields and method inputs of `Route` * The `&Uri` request guard is now `&Origin` * The `uri!` macro produces an `Origin` instead of a `Uri` The strict nature of URI parsing cascaded into the following changes: * Several `Route` methods now `panic!` on invalid URIs * The `Rocket::mount()` method is (correctly) stricter with URIs * The `Redirect` constructors take a `TryInto<Uri>` type * Dispatching of a `LocalRequest` correctly validates URIs Overall, URIs are now properly and uniformly handled throughout Rocket's codebase, resulting in a more reliable and correct system. In addition to these URI changes, the following changes are also part of this commit: * The `LocalRequest::cloned_dispatch()` method was removed in favor of chaining `.clone().dispatch()`. * The entire Rocket codebase uses `crate` instead of `pub(crate)` as a visibility modifier. * Rocket uses the `crate_visibility_modifier` and `try_from` features. A note on unsafety: this commit introduces many uses of `unsafe` in the URI parser. All of these uses are a result of unsafely transforming byte slices (`&[u8]` or similar) into strings (`&str`). The parser ensures that these casts are safe, but of course, we must label their use `unsafe`. The parser was written to be as generic and efficient as possible and thus can parse directly from byte sources. Rocket, however, does not make use of this fact and so would be able to remove all uses of `unsafe` by parsing from an existing `&str`. This should be considered in the future. Fixes #443. Resolves #263.
2018-07-29 01:26:15 +00:00
use http::ext::IntoOwned;
use http::uri::{self, Origin};
/// A route: a method, its handler, path, rank, and format/media type.
Overhaul URI types. This is fairly large commit with several entangled logical changes. The primary change in this commit is to completely overhaul how URI handling in Rocket works. Prior to this commit, the `Uri` type acted as an origin API. Its parser was minimal and lenient, allowing URIs that were invalid according to RFC 7230. By contrast, the new `Uri` type brings with it a strict RFC 7230 compliant parser. The `Uri` type now represents any kind of valid URI, not simply `Origin` types. Three new URI types were introduced: * `Origin` - represents valid origin URIs * `Absolute` - represents valid absolute URIs * `Authority` - represents valid authority URIs The `Origin` type replaces `Uri` in many cases: * As fields and method inputs of `Route` * The `&Uri` request guard is now `&Origin` * The `uri!` macro produces an `Origin` instead of a `Uri` The strict nature of URI parsing cascaded into the following changes: * Several `Route` methods now `panic!` on invalid URIs * The `Rocket::mount()` method is (correctly) stricter with URIs * The `Redirect` constructors take a `TryInto<Uri>` type * Dispatching of a `LocalRequest` correctly validates URIs Overall, URIs are now properly and uniformly handled throughout Rocket's codebase, resulting in a more reliable and correct system. In addition to these URI changes, the following changes are also part of this commit: * The `LocalRequest::cloned_dispatch()` method was removed in favor of chaining `.clone().dispatch()`. * The entire Rocket codebase uses `crate` instead of `pub(crate)` as a visibility modifier. * Rocket uses the `crate_visibility_modifier` and `try_from` features. A note on unsafety: this commit introduces many uses of `unsafe` in the URI parser. All of these uses are a result of unsafely transforming byte slices (`&[u8]` or similar) into strings (`&str`). The parser ensures that these casts are safe, but of course, we must label their use `unsafe`. The parser was written to be as generic and efficient as possible and thus can parse directly from byte sources. Rocket, however, does not make use of this fact and so would be able to remove all uses of `unsafe` by parsing from an existing `&str`. This should be considered in the future. Fixes #443. Resolves #263.
2018-07-29 01:26:15 +00:00
#[derive(Clone)]
pub struct Route {
/// The name of this route, if one was given.
pub name: Option<&'static str>,
/// The method this route matches against.
pub method: Method,
2017-06-30 20:17:40 +00:00
/// The function that should be called when the route matches.
pub handler: Box<Handler>,
/// The base mount point of this `Route`.
Overhaul URI types. This is fairly large commit with several entangled logical changes. The primary change in this commit is to completely overhaul how URI handling in Rocket works. Prior to this commit, the `Uri` type acted as an origin API. Its parser was minimal and lenient, allowing URIs that were invalid according to RFC 7230. By contrast, the new `Uri` type brings with it a strict RFC 7230 compliant parser. The `Uri` type now represents any kind of valid URI, not simply `Origin` types. Three new URI types were introduced: * `Origin` - represents valid origin URIs * `Absolute` - represents valid absolute URIs * `Authority` - represents valid authority URIs The `Origin` type replaces `Uri` in many cases: * As fields and method inputs of `Route` * The `&Uri` request guard is now `&Origin` * The `uri!` macro produces an `Origin` instead of a `Uri` The strict nature of URI parsing cascaded into the following changes: * Several `Route` methods now `panic!` on invalid URIs * The `Rocket::mount()` method is (correctly) stricter with URIs * The `Redirect` constructors take a `TryInto<Uri>` type * Dispatching of a `LocalRequest` correctly validates URIs Overall, URIs are now properly and uniformly handled throughout Rocket's codebase, resulting in a more reliable and correct system. In addition to these URI changes, the following changes are also part of this commit: * The `LocalRequest::cloned_dispatch()` method was removed in favor of chaining `.clone().dispatch()`. * The entire Rocket codebase uses `crate` instead of `pub(crate)` as a visibility modifier. * Rocket uses the `crate_visibility_modifier` and `try_from` features. A note on unsafety: this commit introduces many uses of `unsafe` in the URI parser. All of these uses are a result of unsafely transforming byte slices (`&[u8]` or similar) into strings (`&str`). The parser ensures that these casts are safe, but of course, we must label their use `unsafe`. The parser was written to be as generic and efficient as possible and thus can parse directly from byte sources. Rocket, however, does not make use of this fact and so would be able to remove all uses of `unsafe` by parsing from an existing `&str`. This should be considered in the future. Fixes #443. Resolves #263.
2018-07-29 01:26:15 +00:00
pub base: Origin<'static>,
/// The uri (in Rocket's route format) that should be matched against. This
/// URI already includes the base mount point.
pub uri: Origin<'static>,
/// The rank of this route. Lower ranks have higher priorities.
pub rank: isize,
2017-06-30 20:17:40 +00:00
/// The media type this route matches against, if any.
pub format: Option<MediaType>,
/// Cached metadata that aids in routing later.
crate metadata: Metadata
}
#[derive(Debug, Default, Clone)]
crate struct Metadata {
crate path_segments: Vec<RouteSegment<'static>>,
crate query_segments: Option<Vec<RouteSegment<'static>>>,
crate fully_dynamic_query: bool,
}
impl Metadata {
fn from(route: &Route) -> Result<Metadata, RouteUriError> {
let path_segments = RouteSegment::parse_path(&route.uri)
.map(|res| res.map(|s| s.into_owned()))
.collect::<Result<Vec<_>, _>>()?;
let (query_segments, dyn) = match RouteSegment::parse_query(&route.uri) {
Some(results) => {
let segments = results.map(|res| res.map(|s| s.into_owned()))
.collect::<Result<Vec<_>, _>>()?;
let dynamic = !segments.iter().any(|s| s.kind == Kind::Static);
(Some(segments), dynamic)
}
None => (None, true)
};
Ok(Metadata { path_segments, query_segments, fully_dynamic_query: dyn })
}
}
#[inline(always)]
fn default_rank(route: &Route) -> isize {
let static_path = route.metadata.path_segments.iter().all(|s| s.kind == Kind::Static);
let partly_static_query = route.uri.query().map(|_| !route.metadata.fully_dynamic_query);
match (static_path, partly_static_query) {
(true, Some(true)) => -6, // static path, partly static query
(true, Some(false)) => -5, // static path, fully dynamic query
(true, None) => -4, // static path, no query
(false, Some(true)) => -3, // dynamic path, partly static query
(false, Some(false)) => -2, // dynamic path, fully dynamic query
(false, None) => -1, // dynamic path, no query
}
}
fn panic<U: Display, E: Display, T>(uri: U, e: E) -> T {
panic!("invalid URI '{}' used to construct route: {}", uri, e)
}
impl Route {
2017-06-30 20:17:40 +00:00
/// Creates a new route with the given method, path, and handler with a base
/// of `/`.
///
2017-06-30 20:17:40 +00:00
/// # Ranking
///
/// The route's rank is set so that routes with static paths (no dynamic
/// parameters) are ranked higher than routes with dynamic paths, routes
/// with query strings with static segments are ranked higher than routes
/// with fully dynamic queries, and routes with queries are ranked higher
/// than routes without queries. This default ranking is summarized by the
/// table below:
2017-06-30 20:17:40 +00:00
///
/// | static path | query | rank |
/// |-------------|---------------|------|
/// | yes | partly static | -6 |
/// | yes | fully dynamic | -5 |
/// | yes | none | -4 |
/// | no | partly static | -3 |
/// | no | fully dynamic | -2 |
/// | no | none | -1 |
2017-06-30 20:17:40 +00:00
///
/// # Example
///
/// ```rust
/// use rocket::Route;
2017-06-30 20:17:40 +00:00
/// use rocket::http::Method;
/// # use rocket::{Request, Data};
/// # use rocket::handler::Outcome;
/// # fn handler<'r>(request: &'r Request, _data: Data) -> Outcome<'r> {
/// # Outcome::from(request, "Hello, world!")
/// # }
///
/// // this is rank -6 (static path, ~static query)
/// let route = Route::new(Method::Get, "/foo?bar=baz&<zoo>", handler);
/// assert_eq!(route.rank, -6);
///
/// // this is rank -5 (static path, fully dynamic query)
/// let route = Route::new(Method::Get, "/foo?<zoo..>", handler);
/// assert_eq!(route.rank, -5);
2017-06-30 20:17:40 +00:00
///
/// // this is a rank -4 route (static path, no query)
/// let route = Route::new(Method::Get, "/", handler);
/// assert_eq!(route.rank, -4);
2017-06-30 20:17:40 +00:00
///
/// // this is a rank -3 route (dynamic path, ~static query)
/// let route = Route::new(Method::Get, "/foo/<bar>?blue", handler);
/// assert_eq!(route.rank, -3);
2017-06-30 20:17:40 +00:00
///
/// // this is a rank -2 route (dynamic path, fully dynamic query)
/// let route = Route::new(Method::Get, "/<bar>?<blue>", handler);
/// assert_eq!(route.rank, -2);
2017-06-30 20:17:40 +00:00
///
/// // this is a rank -1 route (dynamic path, no query)
/// let route = Route::new(Method::Get, "/<bar>/foo/<baz..>", handler);
/// assert_eq!(route.rank, -1);
2017-06-30 20:17:40 +00:00
/// ```
Overhaul URI types. This is fairly large commit with several entangled logical changes. The primary change in this commit is to completely overhaul how URI handling in Rocket works. Prior to this commit, the `Uri` type acted as an origin API. Its parser was minimal and lenient, allowing URIs that were invalid according to RFC 7230. By contrast, the new `Uri` type brings with it a strict RFC 7230 compliant parser. The `Uri` type now represents any kind of valid URI, not simply `Origin` types. Three new URI types were introduced: * `Origin` - represents valid origin URIs * `Absolute` - represents valid absolute URIs * `Authority` - represents valid authority URIs The `Origin` type replaces `Uri` in many cases: * As fields and method inputs of `Route` * The `&Uri` request guard is now `&Origin` * The `uri!` macro produces an `Origin` instead of a `Uri` The strict nature of URI parsing cascaded into the following changes: * Several `Route` methods now `panic!` on invalid URIs * The `Rocket::mount()` method is (correctly) stricter with URIs * The `Redirect` constructors take a `TryInto<Uri>` type * Dispatching of a `LocalRequest` correctly validates URIs Overall, URIs are now properly and uniformly handled throughout Rocket's codebase, resulting in a more reliable and correct system. In addition to these URI changes, the following changes are also part of this commit: * The `LocalRequest::cloned_dispatch()` method was removed in favor of chaining `.clone().dispatch()`. * The entire Rocket codebase uses `crate` instead of `pub(crate)` as a visibility modifier. * Rocket uses the `crate_visibility_modifier` and `try_from` features. A note on unsafety: this commit introduces many uses of `unsafe` in the URI parser. All of these uses are a result of unsafely transforming byte slices (`&[u8]` or similar) into strings (`&str`). The parser ensures that these casts are safe, but of course, we must label their use `unsafe`. The parser was written to be as generic and efficient as possible and thus can parse directly from byte sources. Rocket, however, does not make use of this fact and so would be able to remove all uses of `unsafe` by parsing from an existing `&str`. This should be considered in the future. Fixes #443. Resolves #263.
2018-07-29 01:26:15 +00:00
///
/// # Panics
///
/// Panics if `path` is not a valid origin URI or Rocket route URI.
pub fn new<S, H>(method: Method, path: S, handler: H) -> Route
where S: AsRef<str>, H: Handler + 'static
{
let mut route = Route::ranked(0, method, path, handler);
route.rank = default_rank(&route);
route
2016-08-23 03:38:39 +00:00
}
2017-06-30 20:17:40 +00:00
/// Creates a new route with the given rank, method, path, and handler with
/// a base of `/`.
///
/// # Example
///
/// ```rust
/// use rocket::Route;
2017-06-30 20:17:40 +00:00
/// use rocket::http::Method;
/// # use rocket::{Request, Data};
/// # use rocket::handler::Outcome;
/// # fn handler<'r>(request: &'r Request, _data: Data) -> Outcome<'r> {
/// # Outcome::from(request, "Hello, world!")
/// # }
2017-06-30 20:17:40 +00:00
///
/// // this is a rank 1 route matching requests to `GET /`
/// let index = Route::ranked(1, Method::Get, "/", handler);
/// ```
Overhaul URI types. This is fairly large commit with several entangled logical changes. The primary change in this commit is to completely overhaul how URI handling in Rocket works. Prior to this commit, the `Uri` type acted as an origin API. Its parser was minimal and lenient, allowing URIs that were invalid according to RFC 7230. By contrast, the new `Uri` type brings with it a strict RFC 7230 compliant parser. The `Uri` type now represents any kind of valid URI, not simply `Origin` types. Three new URI types were introduced: * `Origin` - represents valid origin URIs * `Absolute` - represents valid absolute URIs * `Authority` - represents valid authority URIs The `Origin` type replaces `Uri` in many cases: * As fields and method inputs of `Route` * The `&Uri` request guard is now `&Origin` * The `uri!` macro produces an `Origin` instead of a `Uri` The strict nature of URI parsing cascaded into the following changes: * Several `Route` methods now `panic!` on invalid URIs * The `Rocket::mount()` method is (correctly) stricter with URIs * The `Redirect` constructors take a `TryInto<Uri>` type * Dispatching of a `LocalRequest` correctly validates URIs Overall, URIs are now properly and uniformly handled throughout Rocket's codebase, resulting in a more reliable and correct system. In addition to these URI changes, the following changes are also part of this commit: * The `LocalRequest::cloned_dispatch()` method was removed in favor of chaining `.clone().dispatch()`. * The entire Rocket codebase uses `crate` instead of `pub(crate)` as a visibility modifier. * Rocket uses the `crate_visibility_modifier` and `try_from` features. A note on unsafety: this commit introduces many uses of `unsafe` in the URI parser. All of these uses are a result of unsafely transforming byte slices (`&[u8]` or similar) into strings (`&str`). The parser ensures that these casts are safe, but of course, we must label their use `unsafe`. The parser was written to be as generic and efficient as possible and thus can parse directly from byte sources. Rocket, however, does not make use of this fact and so would be able to remove all uses of `unsafe` by parsing from an existing `&str`. This should be considered in the future. Fixes #443. Resolves #263.
2018-07-29 01:26:15 +00:00
///
/// # Panics
///
/// Panics if `path` is not a valid origin URI or Rocket route URI.
pub fn ranked<S, H>(rank: isize, method: Method, path: S, handler: H) -> Route
where S: AsRef<str>, H: Handler + 'static
{
let path = path.as_ref();
let uri = Origin::parse_route(path)
.unwrap_or_else(|e| panic(path, e))
.to_normalized()
Overhaul URI types. This is fairly large commit with several entangled logical changes. The primary change in this commit is to completely overhaul how URI handling in Rocket works. Prior to this commit, the `Uri` type acted as an origin API. Its parser was minimal and lenient, allowing URIs that were invalid according to RFC 7230. By contrast, the new `Uri` type brings with it a strict RFC 7230 compliant parser. The `Uri` type now represents any kind of valid URI, not simply `Origin` types. Three new URI types were introduced: * `Origin` - represents valid origin URIs * `Absolute` - represents valid absolute URIs * `Authority` - represents valid authority URIs The `Origin` type replaces `Uri` in many cases: * As fields and method inputs of `Route` * The `&Uri` request guard is now `&Origin` * The `uri!` macro produces an `Origin` instead of a `Uri` The strict nature of URI parsing cascaded into the following changes: * Several `Route` methods now `panic!` on invalid URIs * The `Rocket::mount()` method is (correctly) stricter with URIs * The `Redirect` constructors take a `TryInto<Uri>` type * Dispatching of a `LocalRequest` correctly validates URIs Overall, URIs are now properly and uniformly handled throughout Rocket's codebase, resulting in a more reliable and correct system. In addition to these URI changes, the following changes are also part of this commit: * The `LocalRequest::cloned_dispatch()` method was removed in favor of chaining `.clone().dispatch()`. * The entire Rocket codebase uses `crate` instead of `pub(crate)` as a visibility modifier. * Rocket uses the `crate_visibility_modifier` and `try_from` features. A note on unsafety: this commit introduces many uses of `unsafe` in the URI parser. All of these uses are a result of unsafely transforming byte slices (`&[u8]` or similar) into strings (`&str`). The parser ensures that these casts are safe, but of course, we must label their use `unsafe`. The parser was written to be as generic and efficient as possible and thus can parse directly from byte sources. Rocket, however, does not make use of this fact and so would be able to remove all uses of `unsafe` by parsing from an existing `&str`. This should be considered in the future. Fixes #443. Resolves #263.
2018-07-29 01:26:15 +00:00
.into_owned();
let mut route = Route {
name: None,
format: None,
Overhaul URI types. This is fairly large commit with several entangled logical changes. The primary change in this commit is to completely overhaul how URI handling in Rocket works. Prior to this commit, the `Uri` type acted as an origin API. Its parser was minimal and lenient, allowing URIs that were invalid according to RFC 7230. By contrast, the new `Uri` type brings with it a strict RFC 7230 compliant parser. The `Uri` type now represents any kind of valid URI, not simply `Origin` types. Three new URI types were introduced: * `Origin` - represents valid origin URIs * `Absolute` - represents valid absolute URIs * `Authority` - represents valid authority URIs The `Origin` type replaces `Uri` in many cases: * As fields and method inputs of `Route` * The `&Uri` request guard is now `&Origin` * The `uri!` macro produces an `Origin` instead of a `Uri` The strict nature of URI parsing cascaded into the following changes: * Several `Route` methods now `panic!` on invalid URIs * The `Rocket::mount()` method is (correctly) stricter with URIs * The `Redirect` constructors take a `TryInto<Uri>` type * Dispatching of a `LocalRequest` correctly validates URIs Overall, URIs are now properly and uniformly handled throughout Rocket's codebase, resulting in a more reliable and correct system. In addition to these URI changes, the following changes are also part of this commit: * The `LocalRequest::cloned_dispatch()` method was removed in favor of chaining `.clone().dispatch()`. * The entire Rocket codebase uses `crate` instead of `pub(crate)` as a visibility modifier. * Rocket uses the `crate_visibility_modifier` and `try_from` features. A note on unsafety: this commit introduces many uses of `unsafe` in the URI parser. All of these uses are a result of unsafely transforming byte slices (`&[u8]` or similar) into strings (`&str`). The parser ensures that these casts are safe, but of course, we must label their use `unsafe`. The parser was written to be as generic and efficient as possible and thus can parse directly from byte sources. Rocket, however, does not make use of this fact and so would be able to remove all uses of `unsafe` by parsing from an existing `&str`. This should be considered in the future. Fixes #443. Resolves #263.
2018-07-29 01:26:15 +00:00
base: Origin::dummy(),
handler: Box::new(handler),
metadata: Metadata::default(),
method, rank, uri
};
route.update_metadata().unwrap_or_else(|e| panic(path, e));
route
}
/// Updates the cached routing metadata. MUST be called whenver the route's
/// URI is set or changes.
fn update_metadata(&mut self) -> Result<(), RouteUriError> {
let new_metadata = Metadata::from(&*self)?;
self.metadata = new_metadata;
Ok(())
}
2017-06-30 20:17:40 +00:00
/// Retrieves the path of the base mount point of this route as an `&str`.
///
/// # Example
///
/// ```rust
/// use rocket::Route;
2017-06-30 20:17:40 +00:00
/// use rocket::http::Method;
/// # use rocket::{Request, Data};
/// # use rocket::handler::Outcome;
/// #
/// # fn handler<'r>(request: &'r Request, _data: Data) -> Outcome<'r> {
/// # Outcome::from(request, "Hello, world!")
/// # }
2017-06-30 20:17:40 +00:00
///
/// let mut index = Route::new(Method::Get, "/", handler);
2017-06-30 20:17:40 +00:00
/// assert_eq!(index.base(), "/");
/// assert_eq!(index.base.path(), "/");
/// ```
#[inline]
pub fn base(&self) -> &str {
self.base.path()
}
/// Sets the base mount point of the route to `base` and sets the path to
/// `path`. The `path` should _not_ contains the `base` mount point. If
/// `base` contains a query, it is ignored. Note that `self.uri` will
/// include the new `base` after this method is called.
///
/// # Errors
///
/// Returns an error if any of the following occur:
///
/// * The base mount point contains dynamic parameters.
/// * The base mount point or path contain encoded characters.
/// * The path is not a valid Rocket route URI.
2017-06-30 20:17:40 +00:00
///
/// # Example
///
/// ```rust
/// use rocket::Route;
Overhaul URI types. This is fairly large commit with several entangled logical changes. The primary change in this commit is to completely overhaul how URI handling in Rocket works. Prior to this commit, the `Uri` type acted as an origin API. Its parser was minimal and lenient, allowing URIs that were invalid according to RFC 7230. By contrast, the new `Uri` type brings with it a strict RFC 7230 compliant parser. The `Uri` type now represents any kind of valid URI, not simply `Origin` types. Three new URI types were introduced: * `Origin` - represents valid origin URIs * `Absolute` - represents valid absolute URIs * `Authority` - represents valid authority URIs The `Origin` type replaces `Uri` in many cases: * As fields and method inputs of `Route` * The `&Uri` request guard is now `&Origin` * The `uri!` macro produces an `Origin` instead of a `Uri` The strict nature of URI parsing cascaded into the following changes: * Several `Route` methods now `panic!` on invalid URIs * The `Rocket::mount()` method is (correctly) stricter with URIs * The `Redirect` constructors take a `TryInto<Uri>` type * Dispatching of a `LocalRequest` correctly validates URIs Overall, URIs are now properly and uniformly handled throughout Rocket's codebase, resulting in a more reliable and correct system. In addition to these URI changes, the following changes are also part of this commit: * The `LocalRequest::cloned_dispatch()` method was removed in favor of chaining `.clone().dispatch()`. * The entire Rocket codebase uses `crate` instead of `pub(crate)` as a visibility modifier. * Rocket uses the `crate_visibility_modifier` and `try_from` features. A note on unsafety: this commit introduces many uses of `unsafe` in the URI parser. All of these uses are a result of unsafely transforming byte slices (`&[u8]` or similar) into strings (`&str`). The parser ensures that these casts are safe, but of course, we must label their use `unsafe`. The parser was written to be as generic and efficient as possible and thus can parse directly from byte sources. Rocket, however, does not make use of this fact and so would be able to remove all uses of `unsafe` by parsing from an existing `&str`. This should be considered in the future. Fixes #443. Resolves #263.
2018-07-29 01:26:15 +00:00
/// use rocket::http::{Method, uri::Origin};
/// # use rocket::{Request, Data};
/// # use rocket::handler::Outcome;
/// #
/// # fn handler<'r>(request: &'r Request, _data: Data) -> Outcome<'r> {
/// # Outcome::from(request, "Hello, world!")
/// # }
2017-06-30 20:17:40 +00:00
///
/// let mut index = Route::new(Method::Get, "/", handler);
2017-06-30 20:17:40 +00:00
/// assert_eq!(index.base(), "/");
/// assert_eq!(index.base.path(), "/");
///
/// let new_base = Origin::parse("/greeting").unwrap();
/// let new_uri = Origin::parse("/hi").unwrap();
/// index.set_uri(new_base, new_uri);
/// assert_eq!(index.base(), "/greeting");
/// assert_eq!(index.uri.path(), "/greeting/hi");
2017-06-30 20:17:40 +00:00
/// ```
pub fn set_uri<'a>(
&mut self,
mut base: Origin<'a>,
path: Origin<'a>
) -> Result<(), RouteUriError> {
base.clear_query();
for segment in RouteSegment::parse_path(&base) {
if segment?.kind != Kind::Static {
return Err(RouteUriError::DynamicBase);
}
}
let complete_uri = format!("{}/{}", base, path);
let uri = Origin::parse_route(&complete_uri)?;
self.base = base.to_normalized().into_owned();
self.uri = uri.to_normalized().into_owned();
self.update_metadata()?;
Ok(())
}
}
#[derive(Debug)]
pub enum RouteUriError {
Segment,
Uri(uri::Error<'static>),
DynamicBase,
}
impl<'a> From<(&'a str, SegmentError<'a>)> for RouteUriError {
fn from(_: (&'a str, SegmentError<'a>)) -> Self {
RouteUriError::Segment
}
}
impl<'a> From<uri::Error<'a>> for RouteUriError {
fn from(error: uri::Error<'a>) -> Self {
RouteUriError::Uri(error.into_owned())
}
}
impl fmt::Display for RouteUriError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
RouteUriError::Segment => {
write!(f, "The URI contains malformed dynamic route path segments.")
}
RouteUriError::DynamicBase => {
write!(f, "The mount point contains dynamic parameters.")
}
RouteUriError::Uri(error) => {
write!(f, "Malformed URI: {}", error)
}
}
}
}
impl fmt::Display for Route {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}", Green.paint(&self.method), Blue.paint(&self.uri))?;
if self.rank > 1 {
write!(f, " [{}]", White.paint(&self.rank))?;
}
if let Some(ref format) = self.format {
write!(f, " {}", Yellow.paint(format))?;
}
if let Some(name) = self.name {
write!(f, " {}{}{}",
Cyan.paint("("), Purple.paint(name), Cyan.paint(")"))?;
}
Ok(())
}
}
2016-09-08 07:02:17 +00:00
impl fmt::Debug for Route {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Overhaul URI types. This is fairly large commit with several entangled logical changes. The primary change in this commit is to completely overhaul how URI handling in Rocket works. Prior to this commit, the `Uri` type acted as an origin API. Its parser was minimal and lenient, allowing URIs that were invalid according to RFC 7230. By contrast, the new `Uri` type brings with it a strict RFC 7230 compliant parser. The `Uri` type now represents any kind of valid URI, not simply `Origin` types. Three new URI types were introduced: * `Origin` - represents valid origin URIs * `Absolute` - represents valid absolute URIs * `Authority` - represents valid authority URIs The `Origin` type replaces `Uri` in many cases: * As fields and method inputs of `Route` * The `&Uri` request guard is now `&Origin` * The `uri!` macro produces an `Origin` instead of a `Uri` The strict nature of URI parsing cascaded into the following changes: * Several `Route` methods now `panic!` on invalid URIs * The `Rocket::mount()` method is (correctly) stricter with URIs * The `Redirect` constructors take a `TryInto<Uri>` type * Dispatching of a `LocalRequest` correctly validates URIs Overall, URIs are now properly and uniformly handled throughout Rocket's codebase, resulting in a more reliable and correct system. In addition to these URI changes, the following changes are also part of this commit: * The `LocalRequest::cloned_dispatch()` method was removed in favor of chaining `.clone().dispatch()`. * The entire Rocket codebase uses `crate` instead of `pub(crate)` as a visibility modifier. * Rocket uses the `crate_visibility_modifier` and `try_from` features. A note on unsafety: this commit introduces many uses of `unsafe` in the URI parser. All of these uses are a result of unsafely transforming byte slices (`&[u8]` or similar) into strings (`&str`). The parser ensures that these casts are safe, but of course, we must label their use `unsafe`. The parser was written to be as generic and efficient as possible and thus can parse directly from byte sources. Rocket, however, does not make use of this fact and so would be able to remove all uses of `unsafe` by parsing from an existing `&str`. This should be considered in the future. Fixes #443. Resolves #263.
2018-07-29 01:26:15 +00:00
f.debug_struct("Route")
.field("name", &self.name)
.field("method", &self.method)
.field("base", &self.base)
.field("uri", &self.uri)
.field("rank", &self.rank)
.field("format", &self.format)
.field("metadata", &self.metadata)
Overhaul URI types. This is fairly large commit with several entangled logical changes. The primary change in this commit is to completely overhaul how URI handling in Rocket works. Prior to this commit, the `Uri` type acted as an origin API. Its parser was minimal and lenient, allowing URIs that were invalid according to RFC 7230. By contrast, the new `Uri` type brings with it a strict RFC 7230 compliant parser. The `Uri` type now represents any kind of valid URI, not simply `Origin` types. Three new URI types were introduced: * `Origin` - represents valid origin URIs * `Absolute` - represents valid absolute URIs * `Authority` - represents valid authority URIs The `Origin` type replaces `Uri` in many cases: * As fields and method inputs of `Route` * The `&Uri` request guard is now `&Origin` * The `uri!` macro produces an `Origin` instead of a `Uri` The strict nature of URI parsing cascaded into the following changes: * Several `Route` methods now `panic!` on invalid URIs * The `Rocket::mount()` method is (correctly) stricter with URIs * The `Redirect` constructors take a `TryInto<Uri>` type * Dispatching of a `LocalRequest` correctly validates URIs Overall, URIs are now properly and uniformly handled throughout Rocket's codebase, resulting in a more reliable and correct system. In addition to these URI changes, the following changes are also part of this commit: * The `LocalRequest::cloned_dispatch()` method was removed in favor of chaining `.clone().dispatch()`. * The entire Rocket codebase uses `crate` instead of `pub(crate)` as a visibility modifier. * Rocket uses the `crate_visibility_modifier` and `try_from` features. A note on unsafety: this commit introduces many uses of `unsafe` in the URI parser. All of these uses are a result of unsafely transforming byte slices (`&[u8]` or similar) into strings (`&str`). The parser ensures that these casts are safe, but of course, we must label their use `unsafe`. The parser was written to be as generic and efficient as possible and thus can parse directly from byte sources. Rocket, however, does not make use of this fact and so would be able to remove all uses of `unsafe` by parsing from an existing `&str`. This should be considered in the future. Fixes #443. Resolves #263.
2018-07-29 01:26:15 +00:00
.finish()
2016-09-08 07:02:17 +00:00
}
}
#[doc(hidden)]
2016-04-03 11:25:37 +00:00
impl<'a> From<&'a StaticRouteInfo> for Route {
fn from(info: &'a StaticRouteInfo) -> Route {
// This should never panic since `info.path` is statically checked.
let mut route = Route::new(info.method, info.path, info.handler);
route.format = info.format.clone();
route.name = Some(info.name);
if let Some(rank) = info.rank {
route.rank = rank;
}
route
2016-04-03 11:25:37 +00:00
}
}