2021-06-07 16:28:40 +02:00
//! Routing between [`Service`]s.
2021-06-06 15:19:54 +02:00
use crate ::{ body ::BoxBody , response ::IntoResponse , ResultExt };
2021-05-30 13:24:03 +02:00
use bytes ::Bytes ;
use futures_util ::{ future , ready };
2021-06-06 20:30:54 +02:00
use http ::{ Method , Request , Response , StatusCode , Uri };
use http_body ::Full ;
2021-06-04 01:00:48 +02:00
use hyper ::Body ;
use itertools ::Itertools ;
2021-05-30 13:24:03 +02:00
use pin_project ::pin_project ;
2021-06-04 01:00:48 +02:00
use regex ::Regex ;
2021-05-30 13:24:03 +02:00
use std ::{
2021-06-04 01:00:48 +02:00
borrow ::Cow ,
2021-05-30 13:24:03 +02:00
convert ::Infallible ,
2021-06-08 12:43:16 +02:00
fmt ,
2021-05-30 13:24:03 +02:00
future ::Future ,
pin ::Pin ,
2021-06-04 01:00:48 +02:00
sync ::Arc ,
2021-05-30 13:24:03 +02:00
task ::{ Context , Poll },
};
2021-05-31 16:28:26 +02:00
use tower ::{
2021-06-04 01:00:48 +02:00
buffer ::Buffer ,
util ::{ BoxService , Oneshot , ServiceExt },
2021-06-01 21:15:48 +02:00
BoxError , Layer , Service , ServiceBuilder ,
2021-05-31 16:28:26 +02:00
};
2021-05-30 13:24:03 +02:00
2021-06-07 15:45:19 +02:00
/// A filter that matches one or more HTTP method.
2021-06-06 11:37:08 +02:00
#[derive(Debug, Copy, Clone)]
pub enum MethodFilter {
2021-06-07 15:45:19 +02:00
/// Match any method.
2021-06-06 11:37:08 +02:00
Any ,
2021-06-07 15:45:19 +02:00
/// Match `CONNECT` requests.
2021-06-06 11:37:08 +02:00
Connect ,
2021-06-07 15:45:19 +02:00
/// Match `DELETE` requests.
2021-06-06 11:37:08 +02:00
Delete ,
2021-06-07 15:45:19 +02:00
/// Match `GET` requests.
2021-06-06 11:37:08 +02:00
Get ,
2021-06-07 15:45:19 +02:00
/// Match `HEAD` requests.
2021-06-06 11:37:08 +02:00
Head ,
2021-06-07 15:45:19 +02:00
/// Match `OPTIONS` requests.
2021-06-06 11:37:08 +02:00
Options ,
2021-06-07 15:45:19 +02:00
/// Match `PATCH` requests.
2021-06-06 11:37:08 +02:00
Patch ,
2021-06-07 15:45:19 +02:00
/// Match `POST` requests.
2021-06-06 11:37:08 +02:00
Post ,
2021-06-07 15:45:19 +02:00
/// Match `PUT` requests.
2021-06-06 11:37:08 +02:00
Put ,
2021-06-07 15:45:19 +02:00
/// Match `TRACE` requests.
2021-06-06 11:37:08 +02:00
Trace ,
}
impl MethodFilter {
#[allow(clippy::match_like_matches_macro)]
2021-06-06 15:19:54 +02:00
pub ( crate ) fn matches ( self , method : & Method ) -> bool {
2021-06-06 11:37:08 +02:00
match ( self , method ) {
( MethodFilter ::Any , _ )
| ( MethodFilter ::Connect , & Method ::CONNECT )
| ( MethodFilter ::Delete , & Method ::DELETE )
| ( MethodFilter ::Get , & Method ::GET )
| ( MethodFilter ::Head , & Method ::HEAD )
| ( MethodFilter ::Options , & Method ::OPTIONS )
| ( MethodFilter ::Patch , & Method ::PATCH )
| ( MethodFilter ::Post , & Method ::POST )
| ( MethodFilter ::Put , & Method ::PUT )
| ( MethodFilter ::Trace , & Method ::TRACE ) => true ,
_ => false ,
}
}
}
2021-06-07 15:45:19 +02:00
/// A route that sends requests to one of two [`Service`]s depending on the
/// path.
///
/// Created with [`route`](crate::route). See that function for more details.
#[derive(Debug, Clone)]
2021-06-04 01:00:48 +02:00
pub struct Route < S , F > {
pub ( crate ) pattern : PathPattern ,
pub ( crate ) svc : S ,
pub ( crate ) fallback : F ,
2021-05-30 13:24:03 +02:00
}
2021-06-08 12:43:16 +02:00
/// Trait for building routers.
// TODO(david): this name isn't great
pub trait RoutingDsl : crate ::sealed ::Sealed + Sized {
/// Add another route to the router.
///
/// # Example
///
/// ```rust
/// use tower_web::prelude::*;
///
/// async fn first_handler(request: Request<Body>) { /* ... */ }
///
/// async fn second_handler(request: Request<Body>) { /* ... */ }
///
/// async fn third_handler(request: Request<Body>) { /* ... */ }
///
/// // `GET /` goes to `first_handler`, `POST /` goes to `second_handler`,
/// // and `GET /foo` goes to third_handler.
/// let app = route("/", get(first_handler).post(second_handler))
/// .route("/foo", get(third_handler));
/// ```
2021-06-06 23:58:44 +02:00
fn route < T > ( self , description : & str , svc : T ) -> Route < T , Self >
2021-06-04 01:00:48 +02:00
where
2021-06-06 20:30:54 +02:00
T : Service < Request < Body > , Error = Infallible > + Clone ,
{
Route {
2021-06-06 23:58:44 +02:00
pattern : PathPattern ::new ( description ),
2021-06-06 20:30:54 +02:00
svc ,
fallback : self ,
}
}
2021-06-08 12:43:16 +02:00
/// Nest another service inside this router at the given path.
///
/// See [`nest`] for more details.
2021-06-06 23:58:44 +02:00
fn nest < T > ( self , description : & str , svc : T ) -> Nested < T , Self >
2021-06-06 20:30:54 +02:00
where
T : Service < Request < Body > , Error = Infallible > + Clone ,
{
Nested {
2021-06-06 23:58:44 +02:00
pattern : PathPattern ::new ( description ),
2021-06-06 20:30:54 +02:00
svc ,
fallback : self ,
}
}
2021-05-30 13:24:03 +02:00
2021-06-08 12:43:16 +02:00
/// Create a boxed route trait object.
///
/// This makes it easier to name the types of routers to, for example,
/// return them from functions:
///
/// ```rust
/// use tower_web::{body::BoxBody, routing::BoxRoute, prelude::*};
///
/// async fn first_handler(request: Request<Body>) { /* ... */ }
///
/// async fn second_handler(request: Request<Body>) { /* ... */ }
///
/// async fn third_handler(request: Request<Body>) { /* ... */ }
///
/// fn app() -> BoxRoute<BoxBody> {
/// route("/", get(first_handler).post(second_handler))
/// .route("/foo", get(third_handler))
/// .boxed()
/// }
/// ```
///
/// It also helps with compile times when you have a very large number of
/// routes.
2021-06-06 20:30:54 +02:00
fn boxed < B > ( self ) -> BoxRoute < B >
2021-05-30 13:24:03 +02:00
where
2021-06-04 01:00:48 +02:00
Self : Service < Request < Body > , Response = Response < B > , Error = Infallible > + Send + 'static ,
< Self as Service < Request < Body >>> ::Future : Send ,
2021-06-06 20:30:54 +02:00
B : http_body ::Body < Data = Bytes > + Send + Sync + 'static ,
B ::Error : Into < BoxError > + Send + Sync + 'static ,
2021-05-30 13:24:03 +02:00
{
2021-06-04 01:00:48 +02:00
ServiceBuilder ::new ()
. layer_fn ( BoxRoute )
. buffer ( 1024 )
. layer ( BoxService ::layer ())
. service ( self )
2021-05-30 13:24:03 +02:00
}
2021-06-08 12:43:16 +02:00
/// Apply a [`tower::Layer`] to the router.
///
/// All requests to the router will be processed by the layer's
/// corresponding middleware.
///
/// This can be used to add additional processing to a request for a group
/// of routes.
///
/// Note this differes from [`handler::Layered`](crate::handler::Layered)
/// which adds a middleware to a single handler.
///
/// # Example
///
/// Adding the [`tower::limit::ConcurrencyLimit`] middleware to a group of
/// routes can be done like so:
///
/// ```rust
/// use tower_web::prelude::*;
/// use tower::limit::{ConcurrencyLimitLayer, ConcurrencyLimit};
///
/// async fn first_handler(request: Request<Body>) { /* ... */ }
///
/// async fn second_handler(request: Request<Body>) { /* ... */ }
///
/// async fn third_handler(request: Request<Body>) { /* ... */ }
///
/// // All requests to `handler` and `other_handler` will be sent through
/// // `ConcurrencyLimit`
/// let app = route("/", get(first_handler))
/// .route("/foo", get(second_handler))
/// .layer(ConcurrencyLimitLayer::new(64))
/// // Request to `GET /bar` will go directly to `third_handler` and
/// // wont be sent through `ConcurrencyLimit`
/// .route("/bar", get(third_handler));
/// # async {
/// # hyper::Server::bind(&"".parse().unwrap()).serve(tower::make::Shared::new(app)).await;
/// # };
/// ```
///
/// This is commonly used to add middleware such as tracing/logging to your
/// entire app:
///
/// ```rust
/// use tower_web::prelude::*;
/// use tower_http::trace::TraceLayer;
///
/// async fn first_handler(request: Request<Body>) { /* ... */ }
///
/// async fn second_handler(request: Request<Body>) { /* ... */ }
///
/// async fn third_handler(request: Request<Body>) { /* ... */ }
///
/// let app = route("/", get(first_handler))
/// .route("/foo", get(second_handler))
/// .route("/bar", get(third_handler))
/// .layer(TraceLayer::new_for_http());
/// ```
///
/// When adding middleware that might fail its required to handle those
/// errors. See [`Layered::handle_error`] for more details.
2021-06-06 20:30:54 +02:00
fn layer < L > ( self , layer : L ) -> Layered < L ::Service >
2021-06-04 01:00:48 +02:00
where
L : Layer < Self > ,
L ::Service : Service < Request < Body >> + Clone ,
{
Layered ( layer . layer ( self ))
2021-05-30 13:24:03 +02:00
}
}
2021-06-06 20:30:54 +02:00
impl < S , F > RoutingDsl for Route < S , F > {}
2021-05-30 13:24:03 +02:00
2021-06-08 12:43:16 +02:00
impl < S , F > crate ::sealed ::Sealed for Route < S , F > {}
2021-06-04 01:00:48 +02:00
impl < S , F , SB , FB > Service < Request < Body >> for Route < S , F >
2021-05-30 13:24:03 +02:00
where
2021-06-04 01:00:48 +02:00
S : Service < Request < Body > , Response = Response < SB > , Error = Infallible > + Clone ,
SB : http_body ::Body < Data = Bytes > + Send + Sync + 'static ,
SB ::Error : Into < BoxError > ,
F : Service < Request < Body > , Response = Response < FB > , Error = Infallible > + Clone ,
FB : http_body ::Body < Data = Bytes > + Send + Sync + 'static ,
FB ::Error : Into < BoxError > ,
2021-05-30 13:24:03 +02:00
{
2021-06-04 01:00:48 +02:00
type Response = Response < BoxBody > ;
type Error = Infallible ;
2021-06-06 23:58:44 +02:00
type Future = RouteFuture < S , F > ;
2021-05-30 13:24:03 +02:00
2021-06-04 01:00:48 +02:00
fn poll_ready ( & mut self , _cx : & mut Context < '_ > ) -> Poll < Result < (), Self ::Error >> {
Poll ::Ready ( Ok (()))
2021-05-30 15:44:26 +02:00
}
2021-06-04 01:00:48 +02:00
fn call ( & mut self , mut req : Request < Body > ) -> Self ::Future {
2021-06-06 23:58:44 +02:00
let f = if let Some ( captures ) = self . pattern . full_match ( req . uri (). path ()) {
2021-06-04 01:00:48 +02:00
insert_url_params ( & mut req , captures );
let response_future = self . svc . clone (). oneshot ( req );
future ::Either ::Left ( BoxResponseBody ( response_future ))
} else {
let response_future = self . fallback . clone (). oneshot ( req );
future ::Either ::Right ( BoxResponseBody ( response_future ))
2021-06-06 23:58:44 +02:00
};
RouteFuture ( f )
}
}
2021-06-07 15:45:19 +02:00
/// The response future for [`Route`].
2021-06-06 23:58:44 +02:00
#[pin_project]
2021-06-07 15:45:19 +02:00
#[derive(Debug)]
2021-06-06 23:58:44 +02:00
pub struct RouteFuture < S , F > (
#[pin]
pub ( crate ) future ::Either <
BoxResponseBody < Oneshot < S , Request < Body >>> ,
BoxResponseBody < Oneshot < F , Request < Body >>> ,
> ,
)
where
S : Service < Request < Body >> ,
F : Service < Request < Body >> ;
impl < S , F , SB , FB > Future for RouteFuture < S , F >
where
S : Service < Request < Body > , Response = Response < SB > , Error = Infallible > ,
SB : http_body ::Body < Data = Bytes > + Send + Sync + 'static ,
SB ::Error : Into < BoxError > ,
F : Service < Request < Body > , Response = Response < FB > , Error = Infallible > ,
FB : http_body ::Body < Data = Bytes > + Send + Sync + 'static ,
FB ::Error : Into < BoxError > ,
{
type Output = Result < Response < BoxBody > , Infallible > ;
fn poll ( self : Pin <& mut Self > , cx : & mut Context < '_ > ) -> Poll < Self ::Output > {
self . project (). 0. poll ( cx )
2021-06-04 01:00:48 +02:00
}
}
2021-05-30 15:44:26 +02:00
2021-06-04 01:00:48 +02:00
#[derive(Debug)]
pub ( crate ) struct UrlParams ( pub ( crate ) Vec < ( String , String ) > );
2021-06-02 22:07:37 +02:00
2021-06-04 01:00:48 +02:00
fn insert_url_params < B > ( req : & mut Request < B > , params : Vec < ( String , String ) > ) {
if let Some ( current ) = req . extensions_mut (). get_mut ::< Option < UrlParams >> () {
let mut current = current . take (). unwrap ();
current . 0. extend ( params );
req . extensions_mut (). insert ( Some ( current ));
} else {
req . extensions_mut (). insert ( Some ( UrlParams ( params )));
2021-05-30 13:24:03 +02:00
}
}
2021-06-07 15:45:19 +02:00
/// A response future that boxes the response body with [`BoxBody`].
2021-05-30 13:24:03 +02:00
#[pin_project]
2021-06-07 15:45:19 +02:00
#[derive(Debug)]
2021-06-06 15:19:54 +02:00
pub struct BoxResponseBody < F > ( #[pin] pub ( crate ) F );
2021-05-30 13:24:03 +02:00
2021-06-01 00:34:09 +02:00
impl < F , B > Future for BoxResponseBody < F >
2021-05-30 13:24:03 +02:00
where
2021-06-01 00:34:09 +02:00
F : Future < Output = Result < Response < B > , Infallible >> ,
2021-06-01 11:23:56 +02:00
B : http_body ::Body < Data = Bytes > + Send + Sync + 'static ,
2021-05-30 13:24:03 +02:00
B ::Error : Into < BoxError > ,
{
2021-06-01 11:23:56 +02:00
type Output = Result < Response < BoxBody > , Infallible > ;
2021-05-30 13:24:03 +02:00
fn poll ( self : Pin <& mut Self > , cx : & mut Context < '_ > ) -> Poll < Self ::Output > {
2021-06-01 00:34:09 +02:00
let response : Response < B > = ready! ( self . project (). 0. poll ( cx )). unwrap_infallible ();
2021-05-30 13:24:03 +02:00
let response = response . map ( | body | {
2021-06-01 00:34:09 +02:00
let body = body . map_err ( Into ::into );
2021-05-30 13:24:03 +02:00
BoxBody ::new ( body )
});
Poll ::Ready ( Ok ( response ))
}
}
2021-05-30 15:44:26 +02:00
2021-06-07 15:45:19 +02:00
/// A [`Service`] that responds with `404 Not Found` to all requests.
///
/// This is used as the bottom service in a router stack. You shouldn't have to
/// use to manually.
#[derive(Debug, Clone, Copy)]
2021-06-04 01:00:48 +02:00
pub struct EmptyRouter ;
2021-06-06 20:30:54 +02:00
impl RoutingDsl for EmptyRouter {}
2021-05-31 16:28:26 +02:00
2021-06-08 12:43:16 +02:00
impl crate ::sealed ::Sealed for EmptyRouter {}
2021-06-06 23:58:44 +02:00
impl Service < Request < Body >> for EmptyRouter {
2021-06-04 01:00:48 +02:00
type Response = Response < Body > ;
type Error = Infallible ;
2021-06-06 23:58:44 +02:00
type Future = EmptyRouterFuture ;
2021-06-04 01:00:48 +02:00
fn poll_ready ( & mut self , _cx : & mut Context < '_ > ) -> Poll < Result < (), Self ::Error >> {
Poll ::Ready ( Ok (()))
}
2021-06-06 23:58:44 +02:00
fn call ( & mut self , _req : Request < Body > ) -> Self ::Future {
2021-06-04 01:00:48 +02:00
let mut res = Response ::new ( Body ::empty ());
* res . status_mut () = StatusCode ::NOT_FOUND ;
2021-06-06 23:58:44 +02:00
EmptyRouterFuture ( future ::ok ( res ))
2021-06-04 01:00:48 +02:00
}
}
2021-06-06 23:58:44 +02:00
opaque_future! {
2021-06-07 15:45:19 +02:00
/// Response future for [`EmptyRouter`].
2021-06-06 23:58:44 +02:00
pub type EmptyRouterFuture =
future ::Ready < Result < Response < Body > , Infallible >> ;
}
2021-06-04 01:00:48 +02:00
#[derive(Debug, Clone)]
pub ( crate ) struct PathPattern ( Arc < Inner > );
#[derive(Debug)]
struct Inner {
full_path_regex : Regex ,
capture_group_names : Box < [ Bytes ] > ,
}
impl PathPattern {
pub ( crate ) fn new ( pattern : & str ) -> Self {
2021-06-06 23:58:44 +02:00
assert! (
pattern . starts_with ( '/' ),
"Route description must start with a `/`"
);
2021-06-04 01:00:48 +02:00
let mut capture_group_names = Vec ::new ();
let pattern = pattern
. split ( '/' )
. map ( | part | {
if let Some ( key ) = part . strip_prefix ( ':' ) {
capture_group_names . push ( Bytes ::copy_from_slice ( key . as_bytes ()));
Cow ::Owned ( format! ( "(?P< {} >[^/]*)" , key ))
} else {
Cow ::Borrowed ( part )
}
})
. join ( "/" );
let full_path_regex =
2021-06-06 20:30:54 +02:00
Regex ::new ( & format! ( "^ {} " , pattern )). expect ( "invalid regex generated from route" );
2021-06-04 01:00:48 +02:00
Self ( Arc ::new ( Inner {
full_path_regex ,
capture_group_names : capture_group_names . into (),
}))
}
2021-06-06 20:30:54 +02:00
pub ( crate ) fn full_match ( & self , path : & str ) -> Option < Captures > {
self . do_match ( path ). and_then ( | match_ | {
if match_ . full_match {
Some ( match_ . captures )
} else {
None
}
})
}
pub ( crate ) fn prefix_match < 'a > ( & self , path : & 'a str ) -> Option < ( & 'a str , Captures ) > {
self . do_match ( path )
. map ( | match_ | ( match_ . matched , match_ . captures ))
}
fn do_match < 'a > ( & self , path : & 'a str ) -> Option < Match < 'a >> {
2021-06-04 01:00:48 +02:00
self . 0. full_path_regex . captures ( path ). map ( | captures | {
2021-06-06 20:30:54 +02:00
let matched = captures . get ( 0 ). unwrap ();
let full_match = matched . as_str () == path ;
2021-06-04 01:00:48 +02:00
let captures = self
. 0
. capture_group_names
. iter ()
. map ( | bytes | {
std ::str ::from_utf8 ( bytes )
. expect ( "bytes were created from str so is valid utf-8" )
})
. filter_map ( | name | captures . name ( name ). map ( | value | ( name , value . as_str ())))
. map ( | ( key , value ) | ( key . to_string (), value . to_string ()))
. collect ::< Vec < _ >> ();
2021-06-06 20:30:54 +02:00
Match {
captures ,
full_match ,
matched : matched . as_str (),
}
2021-06-04 01:00:48 +02:00
})
}
}
2021-06-06 20:30:54 +02:00
struct Match < 'a > {
captures : Captures ,
// true if regex matched whole path, false if it only matched a prefix
full_match : bool ,
matched : & 'a str ,
}
2021-06-04 01:00:48 +02:00
type Captures = Vec < ( String , String ) > ;
2021-06-08 12:43:16 +02:00
/// A boxed route trait object.
///
/// See [`RoutingDsl::boxed`] for more details.
2021-06-04 01:00:48 +02:00
pub struct BoxRoute < B > ( Buffer < BoxService < Request < Body > , Response < B > , Infallible > , Request < Body >> );
2021-06-08 12:43:16 +02:00
impl < B > fmt ::Debug for BoxRoute < B > {
fn fmt ( & self , f : & mut fmt ::Formatter < '_ > ) -> fmt ::Result {
f . debug_struct ( "BoxRoute" ). finish ()
}
}
2021-06-04 01:00:48 +02:00
impl < B > Clone for BoxRoute < B > {
2021-05-31 16:28:26 +02:00
fn clone ( & self ) -> Self {
2021-06-04 01:00:48 +02:00
Self ( self . 0. clone ())
2021-05-31 16:28:26 +02:00
}
}
2021-06-06 20:30:54 +02:00
impl < B > RoutingDsl for BoxRoute < B > {}
2021-05-31 16:28:26 +02:00
2021-06-08 12:43:16 +02:00
impl < B > crate ::sealed ::Sealed for BoxRoute < B > {}
2021-06-04 01:00:48 +02:00
impl < B > Service < Request < Body >> for BoxRoute < B >
2021-05-31 16:28:26 +02:00
where
2021-06-06 20:30:54 +02:00
B : http_body ::Body < Data = Bytes > + Send + Sync + 'static ,
B ::Error : Into < BoxError > + Send + Sync + 'static ,
2021-05-31 16:28:26 +02:00
{
2021-06-06 20:30:54 +02:00
type Response = Response < BoxBody > ;
2021-06-01 00:34:09 +02:00
type Error = Infallible ;
2021-06-06 23:58:44 +02:00
type Future = BoxRouteFuture < B > ;
2021-05-31 16:28:26 +02:00
#[inline]
2021-06-04 01:00:48 +02:00
fn poll_ready ( & mut self , _cx : & mut Context < '_ > ) -> Poll < Result < (), Self ::Error >> {
Poll ::Ready ( Ok (()))
2021-05-31 16:28:26 +02:00
}
#[inline]
fn call ( & mut self , req : Request < Body > ) -> Self ::Future {
2021-06-06 23:58:44 +02:00
BoxRouteFuture ( self . 0. clone (). oneshot ( req ))
2021-05-31 16:28:26 +02:00
}
}
2021-06-07 15:45:19 +02:00
/// The response future for [`BoxRoute`].
2021-05-31 16:28:26 +02:00
#[pin_project]
2021-06-06 23:58:44 +02:00
pub struct BoxRouteFuture < B > ( #[pin] InnerFuture < B > );
2021-05-31 16:28:26 +02:00
2021-06-04 01:00:48 +02:00
type InnerFuture < B > = Oneshot <
Buffer < BoxService < Request < Body > , Response < B > , Infallible > , Request < Body >> ,
Request < Body > ,
2021-05-31 16:28:26 +02:00
> ;
2021-06-08 12:43:16 +02:00
impl < B > fmt ::Debug for BoxRouteFuture < B > {
fn fmt ( & self , f : & mut fmt ::Formatter < '_ > ) -> fmt ::Result {
f . debug_struct ( "BoxRouteFuture" ). finish ()
}
}
2021-06-06 23:58:44 +02:00
impl < B > Future for BoxRouteFuture < B >
2021-06-01 00:34:09 +02:00
where
2021-06-06 20:30:54 +02:00
B : http_body ::Body < Data = Bytes > + Send + Sync + 'static ,
B ::Error : Into < BoxError > + Send + Sync + 'static ,
2021-06-01 00:34:09 +02:00
{
2021-06-06 20:30:54 +02:00
type Output = Result < Response < BoxBody > , Infallible > ;
2021-05-31 16:28:26 +02:00
fn poll ( self : Pin <& mut Self > , cx : & mut Context < '_ > ) -> Poll < Self ::Output > {
2021-06-04 01:00:48 +02:00
match ready! ( self . project (). 0. poll ( cx )) {
2021-06-06 20:30:54 +02:00
Ok ( res ) => Poll ::Ready ( Ok ( res . map ( BoxBody ::new ))),
2021-06-04 01:00:48 +02:00
Err ( err ) => Poll ::Ready ( Ok ( handle_buffer_error ( err ))),
2021-06-01 00:34:09 +02:00
}
2021-05-31 16:28:26 +02:00
}
}
2021-06-06 20:30:54 +02:00
fn handle_buffer_error ( error : BoxError ) -> Response < BoxBody > {
2021-06-01 00:34:09 +02:00
use tower ::buffer ::error ::{ Closed , ServiceError };
let error = match error . downcast ::< Closed > () {
Ok ( closed ) => {
return Response ::builder ()
. status ( StatusCode ::INTERNAL_SERVER_ERROR )
2021-06-06 20:30:54 +02:00
. body ( BoxBody ::new ( Full ::from ( closed . to_string ())))
2021-06-01 00:34:09 +02:00
. unwrap ();
}
Err ( e ) => e ,
};
let error = match error . downcast ::< ServiceError > () {
Ok ( service_error ) => {
return Response ::builder ()
. status ( StatusCode ::INTERNAL_SERVER_ERROR )
2021-06-06 20:30:54 +02:00
. body ( BoxBody ::new ( Full ::from ( format! ( "Service error: {} . This is a bug in tower-web. All inner services should be infallible. Please file an issue" , service_error ))))
2021-06-01 00:34:09 +02:00
. unwrap ();
}
Err ( e ) => e ,
};
Response ::builder ()
. status ( StatusCode ::INTERNAL_SERVER_ERROR )
2021-06-06 20:30:54 +02:00
. body ( BoxBody ::new ( Full ::from ( format! (
2021-06-01 00:34:09 +02:00
"Uncountered an unknown error: {} . This should never happen. Please file an issue" ,
error
2021-06-06 20:30:54 +02:00
))))
2021-06-01 00:34:09 +02:00
. unwrap ()
}
2021-06-08 12:43:16 +02:00
/// A [`Service`] created from a router by applying a Tower middleware.
///
/// Created with [`RoutingDsl::layer`]. See that method for more details.
2021-06-04 01:00:48 +02:00
#[derive(Clone, Debug)]
pub struct Layered < S > ( S );
2021-06-06 20:30:54 +02:00
impl < S > RoutingDsl for Layered < S > {}
2021-06-04 01:00:48 +02:00
2021-06-08 12:43:16 +02:00
impl < B > crate ::sealed ::Sealed for Layered < B > {}
2021-06-04 01:00:48 +02:00
impl < S > Layered < S > {
2021-06-08 12:43:16 +02:00
/// Create a new [`Layered`] service where errors will be handled using the
/// given closure.
///
/// tower-web requires that services gracefully handles all errors. That
/// means when you apply a Tower middleware that adds a new failure
/// condition you have to handle that as well.
///
/// That can be done using `handle_error` like so:
///
/// ```rust
/// use tower_web::prelude::*;
/// use http::StatusCode;
/// use tower::{BoxError, timeout::TimeoutLayer};
/// use std::time::Duration;
///
/// async fn handler(request: Request<Body>) { /* ... */ }
///
/// // `Timeout` will fail with `BoxError` if the timeout elapses...
/// let layered_handler = route("/", get(handler))
/// .layer(TimeoutLayer::new(Duration::from_secs(30)));
///
/// // ...so we must handle that error
/// let layered_handler = layered_handler.handle_error(|error: BoxError| {
/// if error.is::<tower::timeout::error::Elapsed>() {
/// (
/// StatusCode::REQUEST_TIMEOUT,
/// "request took too long".to_string(),
/// )
/// } else {
/// (
/// StatusCode::INTERNAL_SERVER_ERROR,
/// format!("Unhandled internal error: {}", error),
/// )
/// }
/// });
/// ```
///
/// The closure can return any type that implements [`IntoResponse`].
2021-06-06 22:43:53 +02:00
pub fn handle_error < F , B , Res > ( self , f : F ) -> crate ::service ::HandleError < S , F >
2021-06-04 01:00:48 +02:00
where
S : Service < Request < Body > , Response = Response < B >> + Clone ,
F : FnOnce ( S ::Error ) -> Res ,
2021-06-06 22:41:52 +02:00
Res : IntoResponse ,
2021-06-04 01:00:48 +02:00
B : http_body ::Body < Data = Bytes > + Send + Sync + 'static ,
B ::Error : Into < BoxError > + Send + Sync + 'static ,
{
2021-06-06 22:43:53 +02:00
crate ::service ::HandleError { inner : self . 0 , f }
2021-06-04 01:00:48 +02:00
}
}
impl < S , B > Service < Request < Body >> for Layered < S >
where
2021-06-06 15:19:54 +02:00
S : Service < Request < Body > , Response = Response < B > , Error = Infallible > ,
2021-06-04 01:00:48 +02:00
{
type Response = S ::Response ;
2021-06-06 15:19:54 +02:00
type Error = Infallible ;
2021-06-04 01:00:48 +02:00
type Future = S ::Future ;
#[inline]
fn poll_ready ( & mut self , cx : & mut Context < '_ > ) -> Poll < Result < (), Self ::Error >> {
self . 0. poll_ready ( cx )
}
#[inline]
fn call ( & mut self , req : Request < Body > ) -> Self ::Future {
self . 0. call ( req )
}
}
2021-06-07 16:28:40 +02:00
/// Nest a group of routes (or a [`Service`]) at some path.
2021-06-07 15:45:19 +02:00
///
/// This allows you to break your application into smaller pieces and compose
/// them together. This will strip the matching prefix from the URL so the
/// nested route will only see the part of URL:
///
/// ```
/// use tower_web::{routing::nest, prelude::*};
///
/// async fn users_get(request: Request<Body>) {
/// // `users_get` doesn't see the whole URL. `nest` will strip the matching
/// // `/api` prefix.
/// assert_eq!(request.uri().path(), "/users");
/// }
///
/// async fn users_post(request: Request<Body>) {}
///
/// async fn careers(request: Request<Body>) {}
///
/// let users_api = route("/users", get(users_get).post(users_post));
///
/// let app = nest("/api", users_api).route("/careers", get(careers));
/// # async {
/// # hyper::Server::bind(&"".parse().unwrap()).serve(tower::make::Shared::new(app)).await;
/// # };
/// ```
///
/// Take care when using `nest` together with dynamic routes as nesting also
/// captures from the outer routes:
///
/// ```
/// use tower_web::{routing::nest, prelude::*};
///
/// async fn users_get(request: Request<Body>, params: extract::UrlParamsMap) {
/// // Both `version` and `id` were captured even though `users_api` only
/// // explicitly captures `id`.
/// let version = params.get("version");
/// let id = params.get("id");
/// }
///
/// let users_api = route("/users/:id", get(users_get));
///
/// let app = nest("/:version/api", users_api);
/// # async {
/// # hyper::Server::bind(&"".parse().unwrap()).serve(tower::make::Shared::new(app)).await;
/// # };
/// ```
///
/// `nest` also accepts any [`Service`]. This can for example be used with
/// [`tower_http::services::ServeDir`] to serve static files from a directory:
///
/// ```
/// use tower_web::{
2021-06-08 12:43:16 +02:00
/// routing::nest, service::{get, ServiceExt}, prelude::*,
2021-06-07 15:45:19 +02:00
/// };
/// use tower_http::services::ServeDir;
///
/// // Serves files inside the `public` directory at `GET /public/*`
/// let serve_dir_service = ServeDir::new("public")
/// .handle_error(|error: std::io::Error| { /* ... */ });
///
/// let app = nest("/public", get(serve_dir_service));
/// # async {
/// # hyper::Server::bind(&"".parse().unwrap()).serve(tower::make::Shared::new(app)).await;
/// # };
/// ```
///
/// If necessary you can use [`RoutingDsl::boxed`] to box a group of routes
/// making the type easier to name. This is sometimes useful when working with
/// `nest`.
2021-06-06 23:58:44 +02:00
pub fn nest < S > ( description : & str , svc : S ) -> Nested < S , EmptyRouter >
2021-06-06 20:30:54 +02:00
where
S : Service < Request < Body > , Error = Infallible > + Clone ,
{
Nested {
2021-06-06 23:58:44 +02:00
pattern : PathPattern ::new ( description ),
2021-06-06 20:30:54 +02:00
svc ,
fallback : EmptyRouter ,
}
}
2021-06-07 15:45:19 +02:00
/// A [`Service`] that has been nested inside a router at some path.
///
/// Created with [`nest`] or [`RoutingDsl::nest`].
2021-06-06 20:30:54 +02:00
#[derive(Debug, Clone)]
pub struct Nested < S , F > {
pattern : PathPattern ,
svc : S ,
fallback : F ,
}
impl < S , F > RoutingDsl for Nested < S , F > {}
2021-06-08 12:43:16 +02:00
impl < S , F > crate ::sealed ::Sealed for Nested < S , F > {}
2021-06-06 20:30:54 +02:00
impl < S , F , SB , FB > Service < Request < Body >> for Nested < S , F >
where
S : Service < Request < Body > , Response = Response < SB > , Error = Infallible > + Clone ,
SB : http_body ::Body < Data = Bytes > + Send + Sync + 'static ,
SB ::Error : Into < BoxError > ,
F : Service < Request < Body > , Response = Response < FB > , Error = Infallible > + Clone ,
FB : http_body ::Body < Data = Bytes > + Send + Sync + 'static ,
FB ::Error : Into < BoxError > ,
{
type Response = Response < BoxBody > ;
type Error = Infallible ;
2021-06-06 23:58:44 +02:00
type Future = RouteFuture < S , F > ;
2021-06-06 20:30:54 +02:00
fn poll_ready ( & mut self , _cx : & mut Context < '_ > ) -> Poll < Result < (), Self ::Error >> {
Poll ::Ready ( Ok (()))
}
fn call ( & mut self , mut req : Request < Body > ) -> Self ::Future {
2021-06-06 23:58:44 +02:00
let f = if let Some (( prefix , captures )) = self . pattern . prefix_match ( req . uri (). path ()) {
2021-06-06 20:30:54 +02:00
let without_prefix = strip_prefix ( req . uri (), prefix );
* req . uri_mut () = without_prefix ;
insert_url_params ( & mut req , captures );
let response_future = self . svc . clone (). oneshot ( req );
future ::Either ::Left ( BoxResponseBody ( response_future ))
} else {
let response_future = self . fallback . clone (). oneshot ( req );
future ::Either ::Right ( BoxResponseBody ( response_future ))
2021-06-06 23:58:44 +02:00
};
RouteFuture ( f )
2021-06-06 20:30:54 +02:00
}
}
fn strip_prefix ( uri : & Uri , prefix : & str ) -> Uri {
let path_and_query = if let Some ( path_and_query ) = uri . path_and_query () {
let new_path = if let Some ( path ) = path_and_query . path (). strip_prefix ( prefix ) {
path
} else {
path_and_query . path ()
};
if let Some ( query ) = path_and_query . query () {
Some (
format! ( " {} ? {} " , new_path , query )
. parse ::< http ::uri ::PathAndQuery > ()
. unwrap (),
)
} else {
Some ( new_path . parse (). unwrap ())
}
} else {
None
};
let mut parts = http ::uri ::Parts ::default ();
parts . scheme = uri . scheme (). cloned ();
parts . authority = uri . authority (). cloned ();
parts . path_and_query = path_and_query ;
Uri ::from_parts ( parts ). unwrap ()
}
2021-05-30 15:44:26 +02:00
#[cfg(test)]
mod tests {
use super ::* ;
#[test]
fn test_routing () {
2021-06-04 01:00:48 +02:00
assert_match ( "/" , "/" );
assert_match ( "/foo" , "/foo" );
assert_match ( "/foo/" , "/foo/" );
refute_match ( "/foo" , "/foo/" );
refute_match ( "/foo/" , "/foo" );
assert_match ( "/foo/bar" , "/foo/bar" );
refute_match ( "/foo/bar/" , "/foo/bar" );
refute_match ( "/foo/bar" , "/foo/bar/" );
assert_match ( "/:value" , "/foo" );
assert_match ( "/users/:id" , "/users/1" );
assert_match ( "/users/:id/action" , "/users/42/action" );
refute_match ( "/users/:id/action" , "/users/42" );
refute_match ( "/users/:id" , "/users/42/action" );
2021-05-30 15:44:26 +02:00
}
2021-06-04 01:00:48 +02:00
fn assert_match ( route_spec : & 'static str , path : & 'static str ) {
let route = PathPattern ::new ( route_spec );
2021-05-30 15:44:26 +02:00
assert! (
2021-06-06 20:30:54 +02:00
route . full_match ( path ). is_some (),
2021-06-04 01:00:48 +02:00
"`{}` doesn't match `{}`" ,
path ,
route_spec
2021-05-30 15:44:26 +02:00
);
}
2021-06-04 01:00:48 +02:00
fn refute_match ( route_spec : & 'static str , path : & 'static str ) {
let route = PathPattern ::new ( route_spec );
2021-05-30 15:44:26 +02:00
assert! (
2021-06-06 20:30:54 +02:00
route . full_match ( path ). is_none (),
2021-06-04 01:00:48 +02:00
"`{}` did match `{}` (but shouldn't)" ,
path ,
route_spec
2021-06-02 22:07:37 +02:00
);
}
2021-05-30 15:44:26 +02:00
}