2021-10-24 22:05:16 +02:00
|
|
|
//! Routing between [`Service`]s and handlers.
|
2021-06-07 16:28:40 +02:00
|
|
|
|
2021-10-24 20:52:42 +02:00
|
|
|
use self::future::{EmptyRouterFuture, NestedFuture, RouteFuture, RoutesFuture};
|
2021-07-22 13:23:50 +02:00
|
|
|
use crate::{
|
2021-10-24 20:52:42 +02:00
|
|
|
body::{box_body, Body, BoxBody},
|
2021-10-02 15:43:59 +02:00
|
|
|
clone_box_service::CloneBoxService,
|
2021-08-08 14:45:31 +02:00
|
|
|
extract::{
|
|
|
|
|
connect_info::{Connected, IntoMakeServiceWithConnectInfo},
|
2021-08-18 09:48:36 +02:00
|
|
|
OriginalUri,
|
2021-08-08 14:45:31 +02:00
|
|
|
},
|
2021-10-02 16:04:29 +02:00
|
|
|
util::{ByteStr, PercentDecodedByteStr},
|
2021-08-21 15:01:30 +02:00
|
|
|
BoxError,
|
2021-07-22 13:23:50 +02:00
|
|
|
};
|
2021-05-30 13:24:03 +02:00
|
|
|
use bytes::Bytes;
|
2021-08-07 23:05:53 +02:00
|
|
|
use http::{Request, Response, StatusCode, Uri};
|
2021-10-24 15:22:49 +02:00
|
|
|
use matchit::Node;
|
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-08-21 15:18:05 +02:00
|
|
|
future::ready,
|
2021-07-06 09:40:25 +02:00
|
|
|
marker::PhantomData,
|
2021-05-30 13:24:03 +02:00
|
|
|
task::{Context, Poll},
|
|
|
|
|
};
|
2021-10-24 20:52:42 +02:00
|
|
|
use tower::util::ServiceExt;
|
|
|
|
|
use tower_http::map_response_body::MapResponseBody;
|
2021-08-21 15:01:30 +02:00
|
|
|
use tower_layer::Layer;
|
|
|
|
|
use tower_service::Service;
|
2021-05-30 13:24:03 +02:00
|
|
|
|
2021-08-06 01:15:10 +02:00
|
|
|
pub mod future;
|
2021-10-24 22:05:16 +02:00
|
|
|
pub mod handler_method_router;
|
|
|
|
|
pub mod service_method_router;
|
2021-08-21 15:01:30 +02:00
|
|
|
|
|
|
|
|
mod method_filter;
|
2021-08-19 22:44:26 +02:00
|
|
|
mod or;
|
2021-08-19 21:24:32 +02:00
|
|
|
|
2021-10-24 20:52:42 +02:00
|
|
|
pub use self::method_filter::MethodFilter;
|
2021-08-06 01:15:10 +02:00
|
|
|
|
2021-10-24 22:05:16 +02:00
|
|
|
#[doc(no_inline)]
|
|
|
|
|
pub use self::handler_method_router::{
|
|
|
|
|
any, connect, delete, get, head, on, options, patch, post, put, trace, MethodRouter,
|
|
|
|
|
};
|
|
|
|
|
|
2021-10-24 15:22:49 +02:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
|
|
|
struct RouteId(u64);
|
|
|
|
|
|
|
|
|
|
impl RouteId {
|
|
|
|
|
fn next() -> Self {
|
|
|
|
|
use std::sync::atomic::{AtomicU64, Ordering};
|
|
|
|
|
static ID: AtomicU64 = AtomicU64::new(0);
|
|
|
|
|
Self(ID.fetch_add(1, Ordering::SeqCst))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-19 21:24:32 +02:00
|
|
|
/// The router type for composing handlers and services.
|
2021-10-24 20:52:42 +02:00
|
|
|
pub struct Router<B = Body> {
|
|
|
|
|
routes: Routes<B>,
|
2021-10-24 19:49:31 +02:00
|
|
|
node: Node<RouteId>,
|
2021-08-19 21:24:32 +02:00
|
|
|
}
|
|
|
|
|
|
2021-10-24 20:52:42 +02:00
|
|
|
impl<B> Clone for Router<B> {
|
|
|
|
|
fn clone(&self) -> Self {
|
2021-08-19 21:24:32 +02:00
|
|
|
Self {
|
2021-10-24 20:52:42 +02:00
|
|
|
routes: self.routes.clone(),
|
|
|
|
|
node: self.node.clone(),
|
2021-08-19 21:24:32 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-24 20:52:42 +02:00
|
|
|
impl<B> Default for Router<B>
|
|
|
|
|
where
|
|
|
|
|
B: Send + Sync + 'static,
|
|
|
|
|
{
|
2021-08-19 21:24:32 +02:00
|
|
|
fn default() -> Self {
|
|
|
|
|
Self::new()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-24 20:52:42 +02:00
|
|
|
impl<B> fmt::Debug for Router<B> {
|
2021-10-24 15:22:49 +02:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
f.debug_struct("Router")
|
|
|
|
|
.field("routes", &self.routes)
|
|
|
|
|
.finish()
|
2021-08-19 21:24:32 +02:00
|
|
|
}
|
2021-05-30 13:24:03 +02:00
|
|
|
}
|
|
|
|
|
|
2021-10-24 15:22:49 +02:00
|
|
|
const NEST_TAIL_PARAM: &str = "__axum_nest";
|
|
|
|
|
|
2021-10-24 20:52:42 +02:00
|
|
|
impl<B> Router<B>
|
|
|
|
|
where
|
|
|
|
|
B: Send + Sync + 'static,
|
|
|
|
|
{
|
|
|
|
|
/// Create a new `Router`.
|
|
|
|
|
///
|
|
|
|
|
/// Unless you add additional routes this will respond to `404 Not Found` to
|
|
|
|
|
/// all requests.
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
routes: Routes(CloneBoxService::new(EmptyRouter::not_found())),
|
|
|
|
|
node: Node::new(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-08 12:43:16 +02:00
|
|
|
/// Add another route to the router.
|
|
|
|
|
///
|
2021-08-24 19:29:28 +02:00
|
|
|
/// `path` is a string of path segments separated by `/`. Each segment
|
2021-08-19 22:37:48 +02:00
|
|
|
/// can be either concrete or a capture:
|
|
|
|
|
///
|
|
|
|
|
/// - `/foo/bar/baz` will only match requests where the path is `/foo/bar/bar`.
|
|
|
|
|
/// - `/:foo` will match any route with exactly one segment _and_ it will
|
|
|
|
|
/// capture the first segment and store it at the key `foo`.
|
|
|
|
|
///
|
|
|
|
|
/// `service` is the [`Service`] that should receive the request if the path
|
2021-08-24 19:29:28 +02:00
|
|
|
/// matches `path`.
|
2021-08-19 22:37:48 +02:00
|
|
|
///
|
2021-06-08 12:43:16 +02:00
|
|
|
/// # Example
|
|
|
|
|
///
|
|
|
|
|
/// ```rust
|
2021-10-24 22:05:16 +02:00
|
|
|
/// use axum::{routing::{get, delete}, Router};
|
2021-06-08 12:43:16 +02:00
|
|
|
///
|
2021-08-19 22:37:48 +02:00
|
|
|
/// let app = Router::new()
|
|
|
|
|
/// .route("/", get(root))
|
|
|
|
|
/// .route("/users", get(list_users).post(create_user))
|
|
|
|
|
/// .route("/users/:id", get(show_user))
|
|
|
|
|
/// .route("/api/:version/users/:id/action", delete(do_thing));
|
2021-06-08 12:43:16 +02:00
|
|
|
///
|
2021-08-19 22:37:48 +02:00
|
|
|
/// async fn root() { /* ... */ }
|
2021-06-08 12:43:16 +02:00
|
|
|
///
|
2021-08-19 22:37:48 +02:00
|
|
|
/// async fn list_users() { /* ... */ }
|
|
|
|
|
///
|
|
|
|
|
/// async fn create_user() { /* ... */ }
|
2021-06-08 12:43:16 +02:00
|
|
|
///
|
2021-08-19 22:37:48 +02:00
|
|
|
/// async fn show_user() { /* ... */ }
|
|
|
|
|
///
|
|
|
|
|
/// async fn do_thing() { /* ... */ }
|
2021-06-19 12:50:33 +02:00
|
|
|
/// # async {
|
2021-08-04 15:38:51 +02:00
|
|
|
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
2021-06-19 12:50:33 +02:00
|
|
|
/// # };
|
2021-06-08 12:43:16 +02:00
|
|
|
/// ```
|
2021-08-19 22:37:48 +02:00
|
|
|
///
|
|
|
|
|
/// # Panics
|
|
|
|
|
///
|
2021-10-24 15:22:49 +02:00
|
|
|
/// Panics if the route overlaps with another route:
|
|
|
|
|
///
|
|
|
|
|
/// ```should_panic
|
2021-10-24 22:05:16 +02:00
|
|
|
/// use axum::{routing::get, Router};
|
2021-10-24 15:22:49 +02:00
|
|
|
///
|
|
|
|
|
/// let app = Router::new()
|
|
|
|
|
/// .route("/", get(|| async {}))
|
|
|
|
|
/// .route("/", get(|| async {}));
|
|
|
|
|
/// # async {
|
|
|
|
|
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
|
|
|
|
/// # };
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// This also applies to `nest` which is similar to a wildcard route:
|
|
|
|
|
///
|
|
|
|
|
/// ```should_panic
|
2021-10-24 22:05:16 +02:00
|
|
|
/// use axum::{routing::get, Router};
|
2021-10-24 15:22:49 +02:00
|
|
|
///
|
|
|
|
|
/// let app = Router::new()
|
|
|
|
|
/// // this is similar to `/api/*`
|
|
|
|
|
/// .nest("/api", get(|| async {}))
|
|
|
|
|
/// // which overlaps with this route
|
|
|
|
|
/// .route("/api/users", get(|| async {}));
|
|
|
|
|
/// # async {
|
|
|
|
|
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
|
|
|
|
/// # };
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// Note that routes like `/:key` and `/foo` are considered overlapping:
|
|
|
|
|
///
|
|
|
|
|
/// ```should_panic
|
2021-10-24 22:05:16 +02:00
|
|
|
/// use axum::{routing::get, Router};
|
2021-10-24 15:22:49 +02:00
|
|
|
///
|
|
|
|
|
/// let app = Router::new()
|
|
|
|
|
/// .route("/foo", get(|| async {}))
|
|
|
|
|
/// .route("/:key", get(|| async {}));
|
|
|
|
|
/// # async {
|
|
|
|
|
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
|
|
|
|
/// # };
|
|
|
|
|
/// ```
|
2021-10-24 20:52:42 +02:00
|
|
|
pub fn route<T>(mut self, path: &str, svc: T) -> Self
|
2021-10-24 19:33:03 +02:00
|
|
|
where
|
2021-10-24 20:52:42 +02:00
|
|
|
T: Service<Request<B>, Response = Response<BoxBody>, Error = Infallible>
|
|
|
|
|
+ Clone
|
|
|
|
|
+ Send
|
|
|
|
|
+ 'static,
|
|
|
|
|
T::Future: Send + 'static,
|
2021-10-24 19:33:03 +02:00
|
|
|
{
|
2021-10-24 15:22:49 +02:00
|
|
|
let id = RouteId::next();
|
|
|
|
|
|
2021-10-24 19:49:31 +02:00
|
|
|
if let Err(err) = self.node.insert(path, id) {
|
2021-10-24 15:22:49 +02:00
|
|
|
panic!("Invalid route: {}", err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Router {
|
2021-10-24 20:52:42 +02:00
|
|
|
routes: Routes(CloneBoxService::new(Route {
|
2021-10-24 15:22:49 +02:00
|
|
|
id,
|
|
|
|
|
svc,
|
|
|
|
|
fallback: self.routes,
|
2021-10-24 20:52:42 +02:00
|
|
|
})),
|
2021-10-24 15:22:49 +02:00
|
|
|
node: self.node,
|
|
|
|
|
}
|
2021-06-06 20:30:54 +02:00
|
|
|
}
|
|
|
|
|
|
2021-08-19 22:37:48 +02:00
|
|
|
/// Nest a group of routes (or a [`Service`]) at some path.
|
|
|
|
|
///
|
|
|
|
|
/// This allows you to break your application into smaller pieces and compose
|
|
|
|
|
/// them together.
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// use axum::{
|
2021-10-24 22:05:16 +02:00
|
|
|
/// routing::get,
|
2021-08-19 22:37:48 +02:00
|
|
|
/// Router,
|
|
|
|
|
/// };
|
|
|
|
|
/// use http::Uri;
|
|
|
|
|
///
|
|
|
|
|
/// async fn users_get(uri: Uri) {
|
2021-08-21 15:06:15 +02:00
|
|
|
/// // `uri` will be `/users` since `nest` strips the matching prefix.
|
|
|
|
|
/// // use `OriginalUri` to always get the full URI.
|
2021-08-19 22:37:48 +02:00
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// async fn users_post() {}
|
|
|
|
|
///
|
|
|
|
|
/// async fn careers() {}
|
|
|
|
|
///
|
|
|
|
|
/// let users_api = Router::new().route("/users", get(users_get).post(users_post));
|
|
|
|
|
///
|
2021-08-21 15:06:15 +02:00
|
|
|
/// let app = Router::new()
|
|
|
|
|
/// .nest("/api", users_api)
|
|
|
|
|
/// .route("/careers", get(careers));
|
2021-08-19 22:37:48 +02:00
|
|
|
/// # async {
|
|
|
|
|
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
|
|
|
|
/// # };
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
2021-08-21 15:06:15 +02:00
|
|
|
/// Note that nested routes will not see the orignal request URI but instead
|
|
|
|
|
/// have the matched prefix stripped. This is necessary for services like static
|
|
|
|
|
/// file serving to work. Use [`OriginalUri`] if you need the original request
|
|
|
|
|
/// URI.
|
|
|
|
|
///
|
2021-08-19 22:37:48 +02:00
|
|
|
/// Take care when using `nest` together with dynamic routes as nesting also
|
|
|
|
|
/// captures from the outer routes:
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// use axum::{
|
|
|
|
|
/// extract::Path,
|
2021-10-24 22:05:16 +02:00
|
|
|
/// routing::get,
|
2021-08-19 22:37:48 +02:00
|
|
|
/// Router,
|
|
|
|
|
/// };
|
|
|
|
|
/// use std::collections::HashMap;
|
|
|
|
|
///
|
|
|
|
|
/// async fn users_get(Path(params): Path<HashMap<String, String>>) {
|
|
|
|
|
/// // 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 = Router::new().route("/users/:id", get(users_get));
|
2021-06-08 12:43:16 +02:00
|
|
|
///
|
2021-08-19 22:37:48 +02:00
|
|
|
/// let app = Router::new().nest("/:version/api", users_api);
|
|
|
|
|
/// # async {
|
|
|
|
|
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
|
|
|
|
/// # };
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// `nest` also accepts any [`Service`]. This can for example be used with
|
|
|
|
|
/// [`tower_http::services::ServeDir`] to serve static files from a directory:
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// use axum::{
|
|
|
|
|
/// Router,
|
2021-10-24 22:05:16 +02:00
|
|
|
/// routing::service_method_router::get,
|
2021-10-24 19:33:03 +02:00
|
|
|
/// error_handling::HandleErrorExt,
|
|
|
|
|
/// http::StatusCode,
|
2021-08-19 22:37:48 +02:00
|
|
|
/// };
|
2021-10-24 19:33:03 +02:00
|
|
|
/// use std::{io, convert::Infallible};
|
2021-08-19 22:37:48 +02:00
|
|
|
/// use tower_http::services::ServeDir;
|
|
|
|
|
///
|
|
|
|
|
/// // Serves files inside the `public` directory at `GET /public/*`
|
2021-10-24 19:33:03 +02:00
|
|
|
/// let serve_dir_service = ServeDir::new("public")
|
|
|
|
|
/// .handle_error(|error: io::Error| {
|
|
|
|
|
/// (
|
|
|
|
|
/// StatusCode::INTERNAL_SERVER_ERROR,
|
|
|
|
|
/// format!("Unhandled internal error: {}", error),
|
|
|
|
|
/// )
|
|
|
|
|
/// });
|
2021-08-19 22:37:48 +02:00
|
|
|
///
|
|
|
|
|
/// let app = Router::new().nest("/public", get(serve_dir_service));
|
|
|
|
|
/// # async {
|
|
|
|
|
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
|
|
|
|
/// # };
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
2021-10-24 15:22:49 +02:00
|
|
|
/// # Wildcard routes
|
|
|
|
|
///
|
|
|
|
|
/// Nested routes are similar to wildcard routes. The difference is that
|
|
|
|
|
/// wildcard routes still see the whole URI whereas nested routes will have
|
|
|
|
|
/// the prefix stripped.
|
|
|
|
|
///
|
|
|
|
|
/// ```rust
|
2021-10-24 22:05:16 +02:00
|
|
|
/// use axum::{routing::get, http::Uri, Router};
|
2021-10-24 15:22:49 +02:00
|
|
|
///
|
|
|
|
|
/// let app = Router::new()
|
|
|
|
|
/// .route("/foo/*rest", get(|uri: Uri| async {
|
|
|
|
|
/// // `uri` will contain `/foo`
|
|
|
|
|
/// }))
|
|
|
|
|
/// .nest("/bar", get(|uri: Uri| async {
|
|
|
|
|
/// // `uri` will _not_ contain `/bar`
|
|
|
|
|
/// }));
|
|
|
|
|
/// # async {
|
|
|
|
|
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
|
|
|
|
/// # };
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// # Panics
|
|
|
|
|
///
|
|
|
|
|
/// Panics if the route overlaps with another route. See [`Router::route`]
|
|
|
|
|
/// for more details.
|
|
|
|
|
///
|
2021-08-21 15:06:15 +02:00
|
|
|
/// [`OriginalUri`]: crate::extract::OriginalUri
|
2021-10-24 20:52:42 +02:00
|
|
|
pub fn nest<T>(mut self, path: &str, svc: T) -> Self
|
2021-10-24 19:33:03 +02:00
|
|
|
where
|
2021-10-24 20:52:42 +02:00
|
|
|
T: Service<Request<B>, Response = Response<BoxBody>, Error = Infallible>
|
|
|
|
|
+ Clone
|
|
|
|
|
+ Send
|
|
|
|
|
+ 'static,
|
|
|
|
|
T::Future: Send + 'static,
|
2021-10-24 19:33:03 +02:00
|
|
|
{
|
2021-10-24 15:22:49 +02:00
|
|
|
let id = RouteId::next();
|
|
|
|
|
|
|
|
|
|
if path.contains('*') {
|
|
|
|
|
panic!("Invalid route: nested routes cannot contain wildcards (*)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let path = if path == "/" {
|
|
|
|
|
format!("/*{}", NEST_TAIL_PARAM)
|
|
|
|
|
} else {
|
|
|
|
|
format!("{}/*{}", path, NEST_TAIL_PARAM)
|
|
|
|
|
};
|
|
|
|
|
|
2021-10-24 19:49:31 +02:00
|
|
|
if let Err(err) = self.node.insert(path, id) {
|
2021-10-24 15:22:49 +02:00
|
|
|
panic!("Invalid route: {}", err);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Router {
|
2021-10-24 20:52:42 +02:00
|
|
|
routes: Routes(CloneBoxService::new(Nested {
|
2021-10-24 15:22:49 +02:00
|
|
|
id,
|
|
|
|
|
svc,
|
|
|
|
|
fallback: self.routes,
|
2021-10-24 20:52:42 +02:00
|
|
|
})),
|
2021-10-24 15:22:49 +02:00
|
|
|
node: self.node,
|
|
|
|
|
}
|
2021-06-06 20:30:54 +02:00
|
|
|
}
|
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.
|
|
|
|
|
///
|
2021-08-04 12:09:39 +02:00
|
|
|
/// Note this differs from [`handler::Layered`](crate::handler::Layered)
|
2021-06-08 12:43:16 +02:00
|
|
|
/// 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
|
2021-08-18 00:04:15 +02:00
|
|
|
/// use axum::{
|
2021-10-24 22:05:16 +02:00
|
|
|
/// routing::get,
|
2021-08-19 22:37:48 +02:00
|
|
|
/// Router,
|
2021-08-18 00:04:15 +02:00
|
|
|
/// };
|
2021-06-08 12:43:16 +02:00
|
|
|
/// use tower::limit::{ConcurrencyLimitLayer, ConcurrencyLimit};
|
|
|
|
|
///
|
2021-06-09 09:03:09 +02:00
|
|
|
/// async fn first_handler() { /* ... */ }
|
2021-06-08 12:43:16 +02:00
|
|
|
///
|
2021-06-09 09:03:09 +02:00
|
|
|
/// async fn second_handler() { /* ... */ }
|
2021-06-08 12:43:16 +02:00
|
|
|
///
|
2021-06-09 09:03:09 +02:00
|
|
|
/// async fn third_handler() { /* ... */ }
|
2021-06-08 12:43:16 +02:00
|
|
|
///
|
|
|
|
|
/// // All requests to `handler` and `other_handler` will be sent through
|
|
|
|
|
/// // `ConcurrencyLimit`
|
2021-08-19 22:37:48 +02:00
|
|
|
/// let app = Router::new().route("/", get(first_handler))
|
2021-06-08 12:43:16 +02:00
|
|
|
/// .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 {
|
2021-08-04 15:38:51 +02:00
|
|
|
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
2021-06-08 12:43:16 +02:00
|
|
|
/// # };
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// This is commonly used to add middleware such as tracing/logging to your
|
|
|
|
|
/// entire app:
|
|
|
|
|
///
|
|
|
|
|
/// ```rust
|
2021-08-18 00:04:15 +02:00
|
|
|
/// use axum::{
|
2021-10-24 22:05:16 +02:00
|
|
|
/// routing::get,
|
2021-08-19 22:37:48 +02:00
|
|
|
/// Router,
|
2021-08-18 00:04:15 +02:00
|
|
|
/// };
|
2021-06-08 12:43:16 +02:00
|
|
|
/// use tower_http::trace::TraceLayer;
|
|
|
|
|
///
|
2021-06-09 09:03:09 +02:00
|
|
|
/// async fn first_handler() { /* ... */ }
|
2021-06-08 12:43:16 +02:00
|
|
|
///
|
2021-06-09 09:03:09 +02:00
|
|
|
/// async fn second_handler() { /* ... */ }
|
2021-06-08 12:43:16 +02:00
|
|
|
///
|
2021-06-09 09:03:09 +02:00
|
|
|
/// async fn third_handler() { /* ... */ }
|
2021-06-08 12:43:16 +02:00
|
|
|
///
|
2021-08-19 22:37:48 +02:00
|
|
|
/// let app = Router::new()
|
|
|
|
|
/// .route("/", get(first_handler))
|
2021-06-08 12:43:16 +02:00
|
|
|
/// .route("/foo", get(second_handler))
|
|
|
|
|
/// .route("/bar", get(third_handler))
|
|
|
|
|
/// .layer(TraceLayer::new_for_http());
|
2021-06-19 12:50:33 +02:00
|
|
|
/// # async {
|
2021-08-04 15:38:51 +02:00
|
|
|
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
2021-06-19 12:50:33 +02:00
|
|
|
/// # };
|
2021-06-08 12:43:16 +02:00
|
|
|
/// ```
|
2021-10-24 20:52:42 +02:00
|
|
|
pub fn layer<L, LayeredReqBody, LayeredResBody>(self, layer: L) -> Router<LayeredReqBody>
|
2021-06-04 01:00:48 +02:00
|
|
|
where
|
2021-10-24 20:52:42 +02:00
|
|
|
L: Layer<Routes<B>>,
|
|
|
|
|
L::Service: Service<
|
|
|
|
|
Request<LayeredReqBody>,
|
|
|
|
|
Response = Response<LayeredResBody>,
|
|
|
|
|
Error = Infallible,
|
|
|
|
|
> + Clone
|
|
|
|
|
+ Send
|
|
|
|
|
+ 'static,
|
|
|
|
|
<L::Service as Service<Request<LayeredReqBody>>>::Future: Send + 'static,
|
|
|
|
|
LayeredResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
|
|
|
|
LayeredResBody::Error: Into<BoxError>,
|
2021-06-04 01:00:48 +02:00
|
|
|
{
|
2021-10-24 20:52:42 +02:00
|
|
|
self.map(|svc| MapResponseBody::new(layer.layer(svc), box_body))
|
2021-05-30 13:24:03 +02:00
|
|
|
}
|
2021-06-12 21:44:40 +02:00
|
|
|
|
|
|
|
|
/// Convert this router into a [`MakeService`], that is a [`Service`] who's
|
|
|
|
|
/// response is another service.
|
|
|
|
|
///
|
|
|
|
|
/// This is useful when running your application with hyper's
|
|
|
|
|
/// [`Server`](hyper::server::Server):
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
2021-08-18 00:04:15 +02:00
|
|
|
/// use axum::{
|
2021-10-24 22:05:16 +02:00
|
|
|
/// routing::get,
|
2021-08-19 22:37:48 +02:00
|
|
|
/// Router,
|
2021-08-18 00:04:15 +02:00
|
|
|
/// };
|
2021-06-12 21:44:40 +02:00
|
|
|
///
|
2021-08-19 22:37:48 +02:00
|
|
|
/// let app = Router::new().route("/", get(|| async { "Hi!" }));
|
2021-06-12 21:44:40 +02:00
|
|
|
///
|
|
|
|
|
/// # async {
|
2021-08-04 15:38:51 +02:00
|
|
|
/// axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
|
2021-06-12 21:44:40 +02:00
|
|
|
/// .serve(app.into_make_service())
|
|
|
|
|
/// .await
|
|
|
|
|
/// .expect("server failed");
|
|
|
|
|
/// # };
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// [`MakeService`]: tower::make::MakeService
|
2021-10-24 20:52:42 +02:00
|
|
|
pub fn into_make_service(self) -> IntoMakeService<Self> {
|
2021-10-24 19:49:31 +02:00
|
|
|
IntoMakeService::new(self)
|
2021-06-12 21:44:40 +02:00
|
|
|
}
|
2021-07-31 21:36:30 +02:00
|
|
|
|
|
|
|
|
/// Convert this router into a [`MakeService`], that will store `C`'s
|
|
|
|
|
/// associated `ConnectInfo` in a request extension such that [`ConnectInfo`]
|
|
|
|
|
/// can extract it.
|
|
|
|
|
///
|
|
|
|
|
/// This enables extracting things like the client's remote address.
|
|
|
|
|
///
|
|
|
|
|
/// Extracting [`std::net::SocketAddr`] is supported out of the box:
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
2021-08-18 00:04:15 +02:00
|
|
|
/// use axum::{
|
|
|
|
|
/// extract::ConnectInfo,
|
2021-10-24 22:05:16 +02:00
|
|
|
/// routing::get,
|
2021-08-19 22:37:48 +02:00
|
|
|
/// Router,
|
2021-08-18 00:04:15 +02:00
|
|
|
/// };
|
2021-07-31 21:36:30 +02:00
|
|
|
/// use std::net::SocketAddr;
|
|
|
|
|
///
|
2021-08-19 22:37:48 +02:00
|
|
|
/// let app = Router::new().route("/", get(handler));
|
2021-07-31 21:36:30 +02:00
|
|
|
///
|
|
|
|
|
/// async fn handler(ConnectInfo(addr): ConnectInfo<SocketAddr>) -> String {
|
|
|
|
|
/// format!("Hello {}", addr)
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// # async {
|
2021-08-04 15:38:51 +02:00
|
|
|
/// axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
|
2021-07-31 21:36:30 +02:00
|
|
|
/// .serve(
|
|
|
|
|
/// app.into_make_service_with_connect_info::<SocketAddr, _>()
|
|
|
|
|
/// )
|
|
|
|
|
/// .await
|
|
|
|
|
/// .expect("server failed");
|
|
|
|
|
/// # };
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// You can implement custom a [`Connected`] like so:
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// use axum::{
|
|
|
|
|
/// extract::connect_info::{ConnectInfo, Connected},
|
2021-10-24 22:05:16 +02:00
|
|
|
/// routing::get,
|
2021-08-19 22:37:48 +02:00
|
|
|
/// Router,
|
2021-07-31 21:36:30 +02:00
|
|
|
/// };
|
|
|
|
|
/// use hyper::server::conn::AddrStream;
|
|
|
|
|
///
|
2021-08-19 22:37:48 +02:00
|
|
|
/// let app = Router::new().route("/", get(handler));
|
2021-07-31 21:36:30 +02:00
|
|
|
///
|
|
|
|
|
/// async fn handler(
|
|
|
|
|
/// ConnectInfo(my_connect_info): ConnectInfo<MyConnectInfo>,
|
|
|
|
|
/// ) -> String {
|
|
|
|
|
/// format!("Hello {:?}", my_connect_info)
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// #[derive(Clone, Debug)]
|
|
|
|
|
/// struct MyConnectInfo {
|
|
|
|
|
/// // ...
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// impl Connected<&AddrStream> for MyConnectInfo {
|
2021-10-19 23:06:15 +02:00
|
|
|
/// fn connect_info(target: &AddrStream) -> Self {
|
2021-07-31 21:36:30 +02:00
|
|
|
/// MyConnectInfo {
|
|
|
|
|
/// // ...
|
|
|
|
|
/// }
|
|
|
|
|
/// }
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// # async {
|
2021-08-04 15:38:51 +02:00
|
|
|
/// axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
|
2021-07-31 21:36:30 +02:00
|
|
|
/// .serve(
|
|
|
|
|
/// app.into_make_service_with_connect_info::<MyConnectInfo, _>()
|
|
|
|
|
/// )
|
|
|
|
|
/// .await
|
|
|
|
|
/// .expect("server failed");
|
|
|
|
|
/// # };
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// See the [unix domain socket example][uds] for an example of how to use
|
|
|
|
|
/// this to collect UDS connection info.
|
|
|
|
|
///
|
|
|
|
|
/// [`MakeService`]: tower::make::MakeService
|
|
|
|
|
/// [`Connected`]: crate::extract::connect_info::Connected
|
|
|
|
|
/// [`ConnectInfo`]: crate::extract::connect_info::ConnectInfo
|
|
|
|
|
/// [uds]: https://github.com/tokio-rs/axum/blob/main/examples/unix_domain_socket.rs
|
2021-08-19 21:24:32 +02:00
|
|
|
pub fn into_make_service_with_connect_info<C, Target>(
|
2021-07-31 21:36:30 +02:00
|
|
|
self,
|
2021-10-24 15:22:49 +02:00
|
|
|
) -> IntoMakeServiceWithConnectInfo<Self, C>
|
2021-07-31 21:36:30 +02:00
|
|
|
where
|
|
|
|
|
C: Connected<Target>,
|
|
|
|
|
{
|
2021-10-24 19:49:31 +02:00
|
|
|
IntoMakeServiceWithConnectInfo::new(self)
|
2021-07-31 21:36:30 +02:00
|
|
|
}
|
2021-08-07 17:09:45 +02:00
|
|
|
|
|
|
|
|
/// Merge two routers into one.
|
|
|
|
|
///
|
|
|
|
|
/// This is useful for breaking apps into smaller pieces and combining them
|
|
|
|
|
/// into one.
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
2021-08-18 00:04:15 +02:00
|
|
|
/// use axum::{
|
2021-10-24 22:05:16 +02:00
|
|
|
/// routing::get,
|
2021-08-19 22:37:48 +02:00
|
|
|
/// Router,
|
2021-08-18 00:04:15 +02:00
|
|
|
/// };
|
2021-08-07 17:09:45 +02:00
|
|
|
/// #
|
|
|
|
|
/// # async fn users_list() {}
|
|
|
|
|
/// # async fn users_show() {}
|
|
|
|
|
/// # async fn teams_list() {}
|
|
|
|
|
///
|
|
|
|
|
/// // define some routes separately
|
2021-08-19 22:44:26 +02:00
|
|
|
/// let user_routes = Router::new()
|
|
|
|
|
/// .route("/users", get(users_list))
|
2021-08-07 17:09:45 +02:00
|
|
|
/// .route("/users/:id", get(users_show));
|
|
|
|
|
///
|
2021-08-19 22:37:48 +02:00
|
|
|
/// let team_routes = Router::new().route("/teams", get(teams_list));
|
2021-08-07 17:09:45 +02:00
|
|
|
///
|
|
|
|
|
/// // combine them into one
|
|
|
|
|
/// let app = user_routes.or(team_routes);
|
|
|
|
|
/// # async {
|
|
|
|
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
|
|
|
|
/// # };
|
|
|
|
|
/// ```
|
2021-10-24 20:52:42 +02:00
|
|
|
pub fn or<T>(self, other: T) -> Self
|
2021-10-24 19:33:03 +02:00
|
|
|
where
|
2021-10-24 20:52:42 +02:00
|
|
|
T: Service<Request<B>, Response = Response<BoxBody>, Error = Infallible>
|
|
|
|
|
+ Clone
|
|
|
|
|
+ Send
|
|
|
|
|
+ 'static,
|
|
|
|
|
T::Future: Send + 'static,
|
2021-10-24 19:33:03 +02:00
|
|
|
{
|
2021-10-24 20:52:42 +02:00
|
|
|
self.map(|first| or::Or {
|
2021-08-19 21:24:32 +02:00
|
|
|
first,
|
2021-08-07 17:09:45 +02:00
|
|
|
second: other,
|
2021-08-19 21:24:32 +02:00
|
|
|
})
|
2021-08-07 17:09:45 +02:00
|
|
|
}
|
2021-08-08 14:30:51 +02:00
|
|
|
|
2021-10-24 20:52:42 +02:00
|
|
|
fn map<F, T, B2>(self, f: F) -> Router<B2>
|
2021-08-19 21:24:32 +02:00
|
|
|
where
|
2021-10-24 20:52:42 +02:00
|
|
|
F: FnOnce(Routes<B>) -> T,
|
|
|
|
|
T: Service<Request<B2>, Response = Response<BoxBody>, Error = Infallible>
|
|
|
|
|
+ Clone
|
|
|
|
|
+ Send
|
|
|
|
|
+ 'static,
|
|
|
|
|
T::Future: Send + 'static,
|
2021-08-19 21:24:32 +02:00
|
|
|
{
|
2021-10-24 15:22:49 +02:00
|
|
|
Router {
|
2021-10-24 20:52:42 +02:00
|
|
|
routes: Routes(CloneBoxService::new(f(self.routes))),
|
2021-10-24 15:22:49 +02:00
|
|
|
node: self.node,
|
|
|
|
|
}
|
2021-08-19 21:24:32 +02:00
|
|
|
}
|
|
|
|
|
}
|
2021-06-08 12:43:16 +02:00
|
|
|
|
2021-10-24 20:52:42 +02:00
|
|
|
impl<B> Service<Request<B>> for Router<B>
|
2021-05-30 13:24:03 +02:00
|
|
|
where
|
2021-10-24 20:52:42 +02:00
|
|
|
B: Send + Sync + 'static,
|
2021-05-30 13:24:03 +02:00
|
|
|
{
|
2021-10-24 20:52:42 +02:00
|
|
|
type Response = Response<BoxBody>;
|
2021-10-24 19:33:03 +02:00
|
|
|
type Error = Infallible;
|
2021-10-24 20:52:42 +02:00
|
|
|
type Future = RoutesFuture;
|
2021-05-30 13:24:03 +02:00
|
|
|
|
2021-10-24 15:22:49 +02:00
|
|
|
#[inline]
|
|
|
|
|
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
|
|
|
self.routes.poll_ready(cx)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2021-10-24 20:52:42 +02:00
|
|
|
fn call(&mut self, mut req: Request<B>) -> Self::Future {
|
2021-10-24 15:22:49 +02:00
|
|
|
if req.extensions().get::<OriginalUri>().is_none() {
|
|
|
|
|
let original_uri = OriginalUri(req.uri().clone());
|
|
|
|
|
req.extensions_mut().insert(original_uri);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let path = req.uri().path().to_string();
|
2021-10-24 19:49:31 +02:00
|
|
|
if let Ok(match_) = self.node.at(&path) {
|
2021-10-24 15:22:49 +02:00
|
|
|
let id = *match_.value;
|
|
|
|
|
req.extensions_mut().insert(id);
|
|
|
|
|
|
|
|
|
|
let params = match_
|
|
|
|
|
.params
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|(key, _)| !key.starts_with(NEST_TAIL_PARAM))
|
|
|
|
|
.map(|(key, value)| (key.to_string(), value.to_string()))
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
|
|
if let Some(tail) = match_.params.get(NEST_TAIL_PARAM) {
|
|
|
|
|
UriStack::push(&mut req);
|
|
|
|
|
let new_uri = with_path(req.uri(), tail);
|
|
|
|
|
*req.uri_mut() = new_uri;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
insert_url_params(&mut req, params);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.routes.call(req)
|
2021-05-30 15:44:26 +02:00
|
|
|
}
|
2021-10-24 15:22:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) struct UriStack(Vec<Uri>);
|
|
|
|
|
|
|
|
|
|
impl UriStack {
|
|
|
|
|
fn push<B>(req: &mut Request<B>) {
|
|
|
|
|
let uri = req.uri().clone();
|
2021-05-30 15:44:26 +02:00
|
|
|
|
2021-10-24 15:22:49 +02:00
|
|
|
if let Some(stack) = req.extensions_mut().get_mut::<Self>() {
|
|
|
|
|
stack.0.push(uri);
|
2021-06-04 01:00:48 +02:00
|
|
|
} else {
|
2021-10-24 15:22:49 +02:00
|
|
|
req.extensions_mut().insert(Self(vec![uri]));
|
2021-06-12 23:59:18 +02:00
|
|
|
}
|
2021-06-06 23:58:44 +02:00
|
|
|
}
|
2021-10-24 15:22:49 +02:00
|
|
|
|
|
|
|
|
pub(crate) fn pop<B>(req: &mut Request<B>) -> Option<Uri> {
|
|
|
|
|
req.extensions_mut()
|
|
|
|
|
.get_mut::<Self>()
|
|
|
|
|
.and_then(|stack| stack.0.pop())
|
|
|
|
|
}
|
2021-06-06 23:58:44 +02:00
|
|
|
}
|
|
|
|
|
|
2021-10-02 16:04:29 +02:00
|
|
|
// we store the potential error here such that users can handle invalid path
|
|
|
|
|
// params using `Result<Path<T>, _>`. That wouldn't be possible if we
|
|
|
|
|
// returned an error immediately when decoding the param
|
|
|
|
|
pub(crate) struct UrlParams(
|
|
|
|
|
pub(crate) Result<Vec<(ByteStr, PercentDecodedByteStr)>, InvalidUtf8InPathParam>,
|
|
|
|
|
);
|
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)>) {
|
2021-06-13 13:06:33 +02:00
|
|
|
let params = params
|
|
|
|
|
.into_iter()
|
2021-10-02 16:04:29 +02:00
|
|
|
.map(|(k, v)| {
|
|
|
|
|
if let Some(decoded) = PercentDecodedByteStr::new(v) {
|
|
|
|
|
Ok((ByteStr::new(k), decoded))
|
|
|
|
|
} else {
|
|
|
|
|
Err(InvalidUtf8InPathParam {
|
|
|
|
|
key: ByteStr::new(k),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.collect::<Result<Vec<_>, _>>();
|
2021-06-13 13:06:33 +02:00
|
|
|
|
2021-06-04 01:00:48 +02:00
|
|
|
if let Some(current) = req.extensions_mut().get_mut::<Option<UrlParams>>() {
|
2021-10-02 16:04:29 +02:00
|
|
|
match params {
|
|
|
|
|
Ok(params) => {
|
|
|
|
|
let mut current = current.take().unwrap();
|
|
|
|
|
if let Ok(current) = &mut current.0 {
|
|
|
|
|
current.extend(params);
|
|
|
|
|
}
|
|
|
|
|
req.extensions_mut().insert(Some(current));
|
|
|
|
|
}
|
|
|
|
|
Err(err) => {
|
|
|
|
|
req.extensions_mut().insert(Some(UrlParams(Err(err))));
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-04 01:00:48 +02:00
|
|
|
} else {
|
2021-10-02 16:04:29 +02:00
|
|
|
req.extensions_mut().insert(Some(UrlParams(params)));
|
2021-05-30 13:24:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-02 16:04:29 +02:00
|
|
|
pub(crate) struct InvalidUtf8InPathParam {
|
|
|
|
|
pub(crate) key: ByteStr,
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-31 21:05:53 +02:00
|
|
|
/// A [`Service`] that responds with `404 Not Found` or `405 Method not allowed`
|
|
|
|
|
/// to all requests.
|
2021-06-07 15:45:19 +02:00
|
|
|
///
|
|
|
|
|
/// This is used as the bottom service in a router stack. You shouldn't have to
|
2021-08-18 15:30:39 -03:00
|
|
|
/// use it manually.
|
2021-07-31 21:05:53 +02:00
|
|
|
pub struct EmptyRouter<E = Infallible> {
|
|
|
|
|
status: StatusCode,
|
|
|
|
|
_marker: PhantomData<fn() -> E>,
|
|
|
|
|
}
|
2021-06-04 01:00:48 +02:00
|
|
|
|
2021-07-06 09:40:25 +02:00
|
|
|
impl<E> EmptyRouter<E> {
|
2021-07-31 21:05:53 +02:00
|
|
|
pub(crate) fn not_found() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
status: StatusCode::NOT_FOUND,
|
|
|
|
|
_marker: PhantomData,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn method_not_allowed() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
status: StatusCode::METHOD_NOT_ALLOWED,
|
|
|
|
|
_marker: PhantomData,
|
|
|
|
|
}
|
2021-07-06 09:40:25 +02:00
|
|
|
}
|
|
|
|
|
}
|
2021-05-31 16:28:26 +02:00
|
|
|
|
2021-07-06 09:40:25 +02:00
|
|
|
impl<E> Clone for EmptyRouter<E> {
|
|
|
|
|
fn clone(&self) -> Self {
|
2021-07-31 21:05:53 +02:00
|
|
|
Self {
|
|
|
|
|
status: self.status,
|
|
|
|
|
_marker: PhantomData,
|
|
|
|
|
}
|
2021-07-06 09:40:25 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<E> fmt::Debug for EmptyRouter<E> {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
f.debug_tuple("EmptyRouter").finish()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-07 17:09:45 +02:00
|
|
|
impl<B, E> Service<Request<B>> for EmptyRouter<E>
|
|
|
|
|
where
|
|
|
|
|
B: Send + Sync + 'static,
|
|
|
|
|
{
|
2021-06-13 10:10:37 +02:00
|
|
|
type Response = Response<BoxBody>;
|
2021-07-06 09:40:25 +02:00
|
|
|
type Error = E;
|
|
|
|
|
type Future = EmptyRouterFuture<E>;
|
2021-06-04 01:00:48 +02:00
|
|
|
|
|
|
|
|
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
|
|
|
Poll::Ready(Ok(()))
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-21 01:00:12 +02:00
|
|
|
fn call(&mut self, mut request: Request<B>) -> Self::Future {
|
|
|
|
|
if self.status == StatusCode::METHOD_NOT_ALLOWED {
|
|
|
|
|
// we're inside a route but there was no method that matched
|
|
|
|
|
// so record that so we can override the status if no other
|
|
|
|
|
// routes match
|
|
|
|
|
request.extensions_mut().insert(NoMethodMatch);
|
|
|
|
|
}
|
2021-08-17 19:00:24 +02:00
|
|
|
|
2021-08-21 01:00:12 +02:00
|
|
|
if self.status == StatusCode::NOT_FOUND
|
|
|
|
|
&& request.extensions().get::<NoMethodMatch>().is_some()
|
|
|
|
|
{
|
|
|
|
|
self.status = StatusCode::METHOD_NOT_ALLOWED;
|
2021-08-17 19:00:24 +02:00
|
|
|
}
|
|
|
|
|
|
2021-08-21 01:00:12 +02:00
|
|
|
let mut res = Response::new(crate::body::empty());
|
|
|
|
|
|
|
|
|
|
res.extensions_mut().insert(FromEmptyRouter { request });
|
|
|
|
|
|
2021-07-31 21:05:53 +02:00
|
|
|
*res.status_mut() = self.status;
|
2021-08-03 15:33:00 +08:00
|
|
|
EmptyRouterFuture {
|
2021-08-21 15:18:05 +02:00
|
|
|
future: ready(Ok(res)),
|
2021-08-03 15:33:00 +08:00
|
|
|
}
|
2021-06-04 01:00:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-21 01:00:12 +02:00
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
|
struct NoMethodMatch;
|
|
|
|
|
|
2021-08-07 17:09:45 +02:00
|
|
|
/// Response extension used by [`EmptyRouter`] to send the request back to [`Or`] so
|
|
|
|
|
/// the other service can be called.
|
|
|
|
|
///
|
|
|
|
|
/// Without this we would loose ownership of the request when calling the first
|
|
|
|
|
/// service in [`Or`]. We also wouldn't be able to identify if the response came
|
|
|
|
|
/// from [`EmptyRouter`] and therefore can be discarded in [`Or`].
|
|
|
|
|
struct FromEmptyRouter<B> {
|
|
|
|
|
request: Request<B>,
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-04 01:00:48 +02:00
|
|
|
#[derive(Debug, Clone)]
|
2021-10-24 20:52:42 +02:00
|
|
|
struct Route<S, T> {
|
2021-10-24 15:22:49 +02:00
|
|
|
id: RouteId,
|
|
|
|
|
svc: S,
|
|
|
|
|
fallback: T,
|
2021-06-04 01:00:48 +02:00
|
|
|
}
|
|
|
|
|
|
2021-10-24 15:22:49 +02:00
|
|
|
impl<B, S, T> Service<Request<B>> for Route<S, T>
|
|
|
|
|
where
|
2021-10-24 19:33:03 +02:00
|
|
|
S: Service<Request<B>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
|
|
|
|
T: Service<Request<B>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
2021-10-24 15:22:49 +02:00
|
|
|
B: Send + Sync + 'static,
|
|
|
|
|
{
|
|
|
|
|
type Response = Response<BoxBody>;
|
2021-10-24 19:33:03 +02:00
|
|
|
type Error = Infallible;
|
2021-10-24 15:22:49 +02:00
|
|
|
type Future = RouteFuture<S, T, B>;
|
2021-06-04 01:00:48 +02:00
|
|
|
|
2021-10-24 15:22:49 +02:00
|
|
|
#[inline]
|
|
|
|
|
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
|
|
|
Poll::Ready(Ok(()))
|
|
|
|
|
}
|
2021-06-04 01:00:48 +02:00
|
|
|
|
2021-10-24 15:22:49 +02:00
|
|
|
fn call(&mut self, req: Request<B>) -> Self::Future {
|
|
|
|
|
match req.extensions().get::<RouteId>() {
|
|
|
|
|
Some(id) => {
|
|
|
|
|
if self.id == *id {
|
|
|
|
|
RouteFuture::a(self.svc.clone().oneshot(req))
|
2021-06-04 01:00:48 +02:00
|
|
|
} else {
|
2021-10-24 15:22:49 +02:00
|
|
|
RouteFuture::b(self.fallback.clone().oneshot(req))
|
2021-06-04 01:00:48 +02:00
|
|
|
}
|
2021-06-06 20:30:54 +02:00
|
|
|
}
|
2021-10-24 15:22:49 +02:00
|
|
|
None => RouteFuture::b(self.fallback.clone().oneshot(req)),
|
|
|
|
|
}
|
2021-06-06 20:30:54 +02:00
|
|
|
}
|
2021-10-24 15:22:49 +02:00
|
|
|
}
|
2021-06-06 20:30:54 +02:00
|
|
|
|
2021-10-24 15:22:49 +02:00
|
|
|
/// A [`Service`] that has been nested inside a router at some path.
|
|
|
|
|
///
|
|
|
|
|
/// Created with [`Router::nest`].
|
|
|
|
|
#[derive(Debug, Clone)]
|
2021-10-24 20:52:42 +02:00
|
|
|
struct Nested<S, T> {
|
2021-10-24 15:22:49 +02:00
|
|
|
id: RouteId,
|
|
|
|
|
svc: S,
|
|
|
|
|
fallback: T,
|
|
|
|
|
}
|
2021-08-08 17:27:23 +02:00
|
|
|
|
2021-10-24 15:22:49 +02:00
|
|
|
impl<B, S, T> Service<Request<B>> for Nested<S, T>
|
|
|
|
|
where
|
2021-10-24 19:33:03 +02:00
|
|
|
S: Service<Request<B>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
|
|
|
|
T: Service<Request<B>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
2021-10-24 15:22:49 +02:00
|
|
|
B: Send + Sync + 'static,
|
|
|
|
|
{
|
|
|
|
|
type Response = Response<BoxBody>;
|
2021-10-24 19:33:03 +02:00
|
|
|
type Error = Infallible;
|
2021-10-24 15:22:49 +02:00
|
|
|
type Future = NestedFuture<S, T, B>;
|
2021-06-06 20:30:54 +02:00
|
|
|
|
2021-10-24 15:22:49 +02:00
|
|
|
#[inline]
|
|
|
|
|
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
|
|
|
Poll::Ready(Ok(()))
|
|
|
|
|
}
|
2021-06-04 01:00:48 +02:00
|
|
|
|
2021-10-24 15:22:49 +02:00
|
|
|
fn call(&mut self, req: Request<B>) -> Self::Future {
|
|
|
|
|
let future = match req.extensions().get::<RouteId>() {
|
|
|
|
|
Some(id) => {
|
|
|
|
|
if self.id == *id {
|
|
|
|
|
RouteFuture::a(self.svc.clone().oneshot(req))
|
|
|
|
|
} else {
|
|
|
|
|
RouteFuture::b(self.fallback.clone().oneshot(req))
|
|
|
|
|
}
|
2021-06-06 20:30:54 +02:00
|
|
|
}
|
2021-10-24 15:22:49 +02:00
|
|
|
None => RouteFuture::b(self.fallback.clone().oneshot(req)),
|
|
|
|
|
};
|
2021-06-04 01:00:48 +02:00
|
|
|
|
2021-10-24 15:22:49 +02:00
|
|
|
NestedFuture { inner: future }
|
|
|
|
|
}
|
2021-06-06 20:30:54 +02:00
|
|
|
}
|
|
|
|
|
|
2021-10-24 15:22:49 +02:00
|
|
|
fn with_path(uri: &Uri, new_path: &str) -> Uri {
|
2021-06-06 20:30:54 +02:00
|
|
|
let path_and_query = if let Some(path_and_query) = uri.path_and_query() {
|
2021-08-02 22:40:33 +02:00
|
|
|
let new_path = if new_path.starts_with('/') {
|
|
|
|
|
Cow::Borrowed(new_path)
|
|
|
|
|
} else {
|
|
|
|
|
Cow::Owned(format!("/{}", new_path))
|
|
|
|
|
};
|
2021-06-12 20:50:30 +02:00
|
|
|
|
2021-06-06 20:30:54 +02:00
|
|
|
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-08-21 15:01:30 +02:00
|
|
|
/// A [`MakeService`] that produces axum router services.
|
|
|
|
|
///
|
|
|
|
|
/// [`MakeService`]: tower::make::MakeService
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct IntoMakeService<S> {
|
|
|
|
|
service: S,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<S> IntoMakeService<S> {
|
|
|
|
|
fn new(service: S) -> Self {
|
|
|
|
|
Self { service }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<S, T> Service<T> for IntoMakeService<S>
|
|
|
|
|
where
|
|
|
|
|
S: Clone,
|
|
|
|
|
{
|
|
|
|
|
type Response = S;
|
|
|
|
|
type Error = Infallible;
|
|
|
|
|
type Future = future::MakeRouteServiceFuture<S>;
|
|
|
|
|
|
|
|
|
|
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
|
|
|
Poll::Ready(Ok(()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn call(&mut self, _target: T) -> Self::Future {
|
|
|
|
|
future::MakeRouteServiceFuture {
|
2021-08-21 15:18:05 +02:00
|
|
|
future: ready(Ok(self.service.clone())),
|
2021-08-21 15:01:30 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-24 20:52:42 +02:00
|
|
|
/// How routes are stored inside a [`Router`].
|
|
|
|
|
///
|
|
|
|
|
/// You normally shouldn't need to care about this type.
|
|
|
|
|
pub struct Routes<B = Body>(CloneBoxService<Request<B>, Response<BoxBody>, Infallible>);
|
|
|
|
|
|
|
|
|
|
impl<ReqBody> Clone for Routes<ReqBody> {
|
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
|
Self(self.0.clone())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<ReqBody> fmt::Debug for Routes<ReqBody> {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
f.debug_struct("Router").finish()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<B> Service<Request<B>> for Routes<B> {
|
|
|
|
|
type Response = Response<BoxBody>;
|
|
|
|
|
type Error = Infallible;
|
|
|
|
|
type Future = future::RoutesFuture;
|
|
|
|
|
|
|
|
|
|
#[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<B>) -> Self::Future {
|
|
|
|
|
future::RoutesFuture {
|
|
|
|
|
future: self.0.call(req),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-30 15:44:26 +02:00
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
|
2021-08-26 20:59:55 +02:00
|
|
|
#[test]
|
|
|
|
|
fn traits() {
|
|
|
|
|
use crate::tests::*;
|
|
|
|
|
|
|
|
|
|
assert_send::<Router<()>>();
|
|
|
|
|
|
|
|
|
|
assert_send::<Route<(), ()>>();
|
|
|
|
|
assert_sync::<Route<(), ()>>();
|
|
|
|
|
|
|
|
|
|
assert_send::<EmptyRouter<NotSendSync>>();
|
|
|
|
|
assert_sync::<EmptyRouter<NotSendSync>>();
|
|
|
|
|
|
|
|
|
|
assert_send::<Nested<(), ()>>();
|
|
|
|
|
assert_sync::<Nested<(), ()>>();
|
|
|
|
|
|
|
|
|
|
assert_send::<IntoMakeService<()>>();
|
|
|
|
|
assert_sync::<IntoMakeService<()>>();
|
|
|
|
|
}
|
2021-05-30 15:44:26 +02:00
|
|
|
}
|