mirror of
https://github.com/tokio-rs/axum.git
synced 2026-09-07 00:00:12 +02:00
fix some todos
This commit is contained in:
@@ -22,8 +22,6 @@ use tower_service::Service;
|
|||||||
/// that handles errors by converting them into responses.
|
/// that handles errors by converting them into responses.
|
||||||
///
|
///
|
||||||
/// See [module docs](self) for more details on axum's error handling model.
|
/// See [module docs](self) for more details on axum's error handling model.
|
||||||
// TODO(david): cannot access state, is that bad? It leads to inference issues and one has to
|
|
||||||
// specify the type manually and risk getting it wrong. So its basically an Extension at that point
|
|
||||||
pub struct HandleErrorLayer<F, T> {
|
pub struct HandleErrorLayer<F, T> {
|
||||||
f: F,
|
f: F,
|
||||||
_extractor: PhantomData<fn() -> T>,
|
_extractor: PhantomData<fn() -> T>,
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ use super::{FromRequest, RequestParts};
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
|
|
||||||
/// TODO(david): docs
|
// document how to extract this from middleware
|
||||||
// TODO(david): document how to extract this from middleware
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
pub struct State<S>(pub S);
|
pub struct State<S>(pub S);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use super::Handler;
|
use super::Handler;
|
||||||
use crate::{extract::State, response::Response};
|
use crate::{response::Response, util::extract_state_assume_present};
|
||||||
use http::Request;
|
use http::Request;
|
||||||
use std::{
|
use std::{
|
||||||
convert::Infallible,
|
convert::Infallible,
|
||||||
@@ -59,18 +59,7 @@ where
|
|||||||
|
|
||||||
let handler = self.handler.clone();
|
let handler = self.handler.clone();
|
||||||
|
|
||||||
// TODO(david): this is duplicated in `axum/src/routing/mod.rs`
|
let state = extract_state_assume_present::<S, _>(&req);
|
||||||
// extract into helper function
|
|
||||||
let State(state) = req
|
|
||||||
.extensions()
|
|
||||||
.get::<State<S>>()
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
panic!(
|
|
||||||
"no state of type `{}` was found. Please file an issue",
|
|
||||||
std::any::type_name::<State<S>>()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.clone();
|
|
||||||
let future = Handler::call(handler, state, req);
|
let future = Handler::call(handler, state, req);
|
||||||
let future = future.map(Ok as _);
|
let future = future.map(Ok as _);
|
||||||
|
|
||||||
|
|||||||
@@ -64,8 +64,7 @@ pub mod future;
|
|||||||
/// See the [module docs](crate::handler) for more details.
|
/// See the [module docs](crate::handler) for more details.
|
||||||
///
|
///
|
||||||
#[doc = include_str!("../docs/debugging_handler_type_errors.md")]
|
#[doc = include_str!("../docs/debugging_handler_type_errors.md")]
|
||||||
// TODO(david): Add back `B = Body` default
|
pub trait Handler<S, T, B = Body>: Clone + Send + Sized + 'static {
|
||||||
pub trait Handler<S, T, B>: Clone + Send + Sized + 'static {
|
|
||||||
/// The type of future calling this handler returns.
|
/// The type of future calling this handler returns.
|
||||||
type Future: Future<Output = Response> + Send + 'static;
|
type Future: Future<Output = Response> + Send + 'static;
|
||||||
|
|
||||||
@@ -151,7 +150,6 @@ pub trait Handler<S, T, B>: Clone + Send + Sized + 'static {
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`Router::fallback`]: crate::routing::Router::fallback
|
/// [`Router::fallback`]: crate::routing::Router::fallback
|
||||||
// TODO(david): remove this
|
|
||||||
fn into_service(self, state: S) -> IntoService<Self, S, T, B> {
|
fn into_service(self, state: S) -> IntoService<Self, S, T, B> {
|
||||||
IntoService::new(self, state)
|
IntoService::new(self, state)
|
||||||
}
|
}
|
||||||
@@ -179,7 +177,6 @@ pub trait Handler<S, T, B>: Clone + Send + Sized + 'static {
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`MakeService`]: tower::make::MakeService
|
/// [`MakeService`]: tower::make::MakeService
|
||||||
// TODO(david): remove this
|
|
||||||
fn into_make_service(self, state: S) -> IntoMakeService<IntoService<Self, S, T, B>> {
|
fn into_make_service(self, state: S) -> IntoMakeService<IntoService<Self, S, T, B>> {
|
||||||
IntoMakeService::new(self.into_service(state))
|
IntoMakeService::new(self.into_service(state))
|
||||||
}
|
}
|
||||||
@@ -212,7 +209,6 @@ pub trait Handler<S, T, B>: Clone + Send + Sized + 'static {
|
|||||||
///
|
///
|
||||||
/// [`MakeService`]: tower::make::MakeService
|
/// [`MakeService`]: tower::make::MakeService
|
||||||
/// [`Router::into_make_service_with_connect_info`]: crate::routing::Router::into_make_service_with_connect_info
|
/// [`Router::into_make_service_with_connect_info`]: crate::routing::Router::into_make_service_with_connect_info
|
||||||
// TODO(david): remove this
|
|
||||||
fn into_make_service_with_connect_info<C>(
|
fn into_make_service_with_connect_info<C>(
|
||||||
self,
|
self,
|
||||||
state: S,
|
state: S,
|
||||||
@@ -350,16 +346,20 @@ where
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::test_helpers::*;
|
use crate::{extract::State, test_helpers::*};
|
||||||
use http::StatusCode;
|
use http::StatusCode;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn handler_into_service() {
|
async fn handler_into_service() {
|
||||||
async fn handle(body: String) -> impl IntoResponse {
|
async fn handle(State(state): State<AppState>, body: String) -> impl IntoResponse {
|
||||||
|
assert_eq!(state.0, 1337);
|
||||||
format!("you said: {}", body)
|
format!("you said: {}", body)
|
||||||
}
|
}
|
||||||
|
|
||||||
let client = TestClient::new(handle.into_service(()));
|
#[derive(Clone)]
|
||||||
|
struct AppState(i32);
|
||||||
|
|
||||||
|
let client = TestClient::new(handle.into_service(AppState(1337)));
|
||||||
|
|
||||||
let res = client.post("/").body("hi there!").send().await;
|
let res = client.post("/").body("hi there!").send().await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
|||||||
+2
-2
@@ -382,8 +382,8 @@
|
|||||||
rust_2018_idioms,
|
rust_2018_idioms,
|
||||||
future_incompatible,
|
future_incompatible,
|
||||||
nonstandard_style,
|
nonstandard_style,
|
||||||
// missing_debug_implementations,
|
missing_debug_implementations,
|
||||||
// missing_docs
|
missing_docs
|
||||||
)]
|
)]
|
||||||
#![deny(unreachable_pub, private_in_public)]
|
#![deny(unreachable_pub, private_in_public)]
|
||||||
#![allow(elided_lifetimes_in_paths, clippy::type_complexity)]
|
#![allow(elided_lifetimes_in_paths, clippy::type_complexity)]
|
||||||
|
|||||||
@@ -400,7 +400,7 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn extracting_state() {
|
async fn extracting_state() {
|
||||||
async fn access_state<B>(req: Request<B>, next: Next<B>) -> impl IntoResponse {
|
async fn access_state<B>(req: Request<B>, _next: Next<B>) -> impl IntoResponse {
|
||||||
let State(state) = req.extensions().get::<State<AppState>>().unwrap().clone();
|
let State(state) = req.extensions().get::<State<AppState>>().unwrap().clone();
|
||||||
state.value
|
state.value
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ impl<T> From<T> for Html<T> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::extract::Extension;
|
use crate::extract::Extension;
|
||||||
use crate::{body::Body, routing::get, Router};
|
use crate::{routing::get, Router};
|
||||||
use axum_core::response::IntoResponse;
|
use axum_core::response::IntoResponse;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use http::{StatusCode, Uri};
|
use http::{StatusCode, Uri};
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ macro_rules! top_level_service_fn {
|
|||||||
$name:ident, $method:ident
|
$name:ident, $method:ident
|
||||||
) => {
|
) => {
|
||||||
$(#[$m])+
|
$(#[$m])+
|
||||||
pub fn $name<T, ReqBody, ResBody, S>(svc: T) -> MethodRouter<S, ReqBody, T::Error, MissingState>
|
pub fn $name<T, ReqBody, ResBody, S>(svc: T) -> MethodRouter<S, MissingState, ReqBody, T::Error>
|
||||||
where
|
where
|
||||||
T: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
|
T: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
|
||||||
T::Future: Send + 'static,
|
T::Future: Send + 'static,
|
||||||
@@ -137,7 +137,7 @@ macro_rules! top_level_handler_fn {
|
|||||||
$name:ident, $method:ident
|
$name:ident, $method:ident
|
||||||
) => {
|
) => {
|
||||||
$(#[$m])+
|
$(#[$m])+
|
||||||
pub fn $name<H, S, T, B>(handler: H) -> MethodRouter<S, B, Infallible, MissingState>
|
pub fn $name<H, S, T, B>(handler: H) -> MethodRouter<S, MissingState, B, Infallible>
|
||||||
where
|
where
|
||||||
H: Handler<S, T, B>,
|
H: Handler<S, T, B>,
|
||||||
B: Send + 'static,
|
B: Send + 'static,
|
||||||
@@ -321,7 +321,7 @@ top_level_service_fn!(trace_service, TRACE);
|
|||||||
pub fn on_service<T, ReqBody, ResBody, S>(
|
pub fn on_service<T, ReqBody, ResBody, S>(
|
||||||
filter: MethodFilter,
|
filter: MethodFilter,
|
||||||
svc: T,
|
svc: T,
|
||||||
) -> MethodRouter<S, ReqBody, T::Error, MissingState>
|
) -> MethodRouter<S, MissingState, ReqBody, T::Error>
|
||||||
where
|
where
|
||||||
T: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
|
T: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
|
||||||
T::Future: Send + 'static,
|
T::Future: Send + 'static,
|
||||||
@@ -386,7 +386,7 @@ where
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn any_service<T, ReqBody, ResBody, S>(
|
pub fn any_service<T, ReqBody, ResBody, S>(
|
||||||
svc: T,
|
svc: T,
|
||||||
) -> MethodRouter<S, ReqBody, T::Error, MissingState>
|
) -> MethodRouter<S, MissingState, ReqBody, T::Error>
|
||||||
where
|
where
|
||||||
T: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
|
T: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
|
||||||
T::Future: Send + 'static,
|
T::Future: Send + 'static,
|
||||||
@@ -429,7 +429,7 @@ top_level_handler_fn!(trace, TRACE);
|
|||||||
pub fn on<H, S, T, B>(
|
pub fn on<H, S, T, B>(
|
||||||
filter: MethodFilter,
|
filter: MethodFilter,
|
||||||
handler: H,
|
handler: H,
|
||||||
) -> MethodRouter<S, B, Infallible, MissingState>
|
) -> MethodRouter<S, MissingState, B, Infallible>
|
||||||
where
|
where
|
||||||
H: Handler<S, T, B>,
|
H: Handler<S, T, B>,
|
||||||
B: Send + 'static,
|
B: Send + 'static,
|
||||||
@@ -476,7 +476,7 @@ where
|
|||||||
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
/// # };
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
pub fn any<H, S, T, B>(handler: H) -> MethodRouter<S, B, Infallible, MissingState>
|
pub fn any<H, S, T, B>(handler: H) -> MethodRouter<S, MissingState, B, Infallible>
|
||||||
where
|
where
|
||||||
H: Handler<S, T, B>,
|
H: Handler<S, T, B>,
|
||||||
B: Send + 'static,
|
B: Send + 'static,
|
||||||
@@ -490,9 +490,7 @@ where
|
|||||||
|
|
||||||
/// A [`Service`] that accepts requests based on a [`MethodFilter`] and
|
/// A [`Service`] that accepts requests based on a [`MethodFilter`] and
|
||||||
/// allows chaining additional handlers and services.
|
/// allows chaining additional handlers and services.
|
||||||
// TODO(david): Bring back `B = Body, E = Infallible` defaults
|
pub struct MethodRouter<S, R = MissingState, B = Body, E = Infallible> {
|
||||||
// TODO(david): think about ordering of type params here
|
|
||||||
pub struct MethodRouter<S, B, E, R> {
|
|
||||||
// Invariant: If `R == MissingState` then `state` is `None`
|
// Invariant: If `R == MissingState` then `state` is `None`
|
||||||
// If `R == WithState` then state is `Some`
|
// If `R == WithState` then state is `Some`
|
||||||
// `R` cannot have other values
|
// `R` cannot have other values
|
||||||
@@ -520,7 +518,7 @@ enum AllowHeader {
|
|||||||
Bytes(BytesMut),
|
Bytes(BytesMut),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B, E, R> fmt::Debug for MethodRouter<S, B, E, R>
|
impl<S, B, E, R> fmt::Debug for MethodRouter<S, R, B, E>
|
||||||
where
|
where
|
||||||
S: fmt::Debug,
|
S: fmt::Debug,
|
||||||
{
|
{
|
||||||
@@ -540,7 +538,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B, E> MethodRouter<S, B, E, MissingState> {
|
impl<S, B, E> MethodRouter<S, MissingState, B, E> {
|
||||||
/// Create a default `MethodRouter` that will respond with `405 Method Not Allowed` to all
|
/// Create a default `MethodRouter` that will respond with `405 Method Not Allowed` to all
|
||||||
/// requests.
|
/// requests.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
@@ -566,8 +564,7 @@ impl<S, B, E> MethodRouter<S, B, E, MissingState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO(david): docs
|
pub fn state(self, state: S) -> MethodRouter<S, WithState, B, E> {
|
||||||
pub fn state(self, state: S) -> MethodRouter<S, B, E, WithState> {
|
|
||||||
MethodRouter {
|
MethodRouter {
|
||||||
state: Some(state),
|
state: Some(state),
|
||||||
get: self.get,
|
get: self.get,
|
||||||
@@ -585,21 +582,19 @@ impl<S, B, E> MethodRouter<S, B, E, MissingState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B, E> MethodRouter<S, B, E, WithState> {
|
impl<S, B, E> MethodRouter<S, WithState, B, E> {
|
||||||
/// TODO(david): docs
|
|
||||||
pub fn with_state(state: S) -> Self {
|
pub fn with_state(state: S) -> Self {
|
||||||
MethodRouter::new().state(state)
|
MethodRouter::new().state(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B, E> MethodRouter<(), B, E, WithState> {
|
impl<B, E> MethodRouter<(), WithState, B, E> {
|
||||||
/// TODO(david): docs
|
|
||||||
pub fn without_state() -> Self {
|
pub fn without_state() -> Self {
|
||||||
MethodRouter::with_state(())
|
MethodRouter::with_state(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B, R> MethodRouter<S, B, Infallible, R>
|
impl<S, B, R> MethodRouter<S, R, B, Infallible>
|
||||||
where
|
where
|
||||||
B: Send + 'static,
|
B: Send + 'static,
|
||||||
S: Clone + Send + Sync + 'static,
|
S: Clone + Send + Sync + 'static,
|
||||||
@@ -645,7 +640,7 @@ where
|
|||||||
chained_handler_fn!(trace, TRACE);
|
chained_handler_fn!(trace, TRACE);
|
||||||
|
|
||||||
#[doc = include_str!("../docs/routing/fallback.md")]
|
#[doc = include_str!("../docs/routing/fallback.md")]
|
||||||
pub fn fallback<H, T>(mut self, handler: H) -> Self
|
pub fn fallback<H, T>(self, handler: H) -> Self
|
||||||
where
|
where
|
||||||
H: Handler<S, T, B>,
|
H: Handler<S, T, B>,
|
||||||
T: 'static,
|
T: 'static,
|
||||||
@@ -654,8 +649,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B, R> MethodRouter<S, B, Infallible, R> {
|
impl<S, B, R> MethodRouter<S, R, B, Infallible> {
|
||||||
pub(crate) fn change_state_marker<R2>(self) -> MethodRouter<S, B, Infallible, R2> {
|
pub(crate) fn change_state_marker<R2>(self) -> MethodRouter<S, R2, B, Infallible> {
|
||||||
MethodRouter {
|
MethodRouter {
|
||||||
state: self.state,
|
state: self.state,
|
||||||
get: self.get,
|
get: self.get,
|
||||||
@@ -673,8 +668,8 @@ impl<S, B, R> MethodRouter<S, B, Infallible, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B> MethodRouter<S, B, Infallible, MissingState> {
|
impl<S, B> MethodRouter<S, MissingState, B, Infallible> {
|
||||||
pub(crate) fn change_state<S2>(self) -> MethodRouter<S2, B, Infallible, MissingState> {
|
pub(crate) fn change_state<S2>(self) -> MethodRouter<S2, MissingState, B, Infallible> {
|
||||||
debug_assert!(self.state.is_none());
|
debug_assert!(self.state.is_none());
|
||||||
MethodRouter {
|
MethodRouter {
|
||||||
state: None,
|
state: None,
|
||||||
@@ -693,7 +688,7 @@ impl<S, B> MethodRouter<S, B, Infallible, MissingState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B> MethodRouter<S, B, Infallible, WithState>
|
impl<S, B> MethodRouter<S, WithState, B, Infallible>
|
||||||
where
|
where
|
||||||
B: Send + 'static,
|
B: Send + 'static,
|
||||||
S: Clone + Send + Sync + 'static,
|
S: Clone + Send + Sync + 'static,
|
||||||
@@ -767,7 +762,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B, E, R> MethodRouter<S, B, E, R> {
|
impl<S, B, E, R> MethodRouter<S, R, B, E> {
|
||||||
/// Chain an additional service that will accept requests matching the given
|
/// Chain an additional service that will accept requests matching the given
|
||||||
/// `MethodFilter`.
|
/// `MethodFilter`.
|
||||||
///
|
///
|
||||||
@@ -837,7 +832,7 @@ impl<S, B, E, R> MethodRouter<S, B, E, R> {
|
|||||||
pub fn layer<L, NewReqBody, NewResBody, NewError>(
|
pub fn layer<L, NewReqBody, NewResBody, NewError>(
|
||||||
self,
|
self,
|
||||||
layer: L,
|
layer: L,
|
||||||
) -> MethodRouter<S, NewReqBody, NewError, R>
|
) -> MethodRouter<S, R, NewReqBody, NewError>
|
||||||
where
|
where
|
||||||
L: Layer<Route<B, E>>,
|
L: Layer<Route<B, E>>,
|
||||||
L::Service: Service<Request<NewReqBody>, Response = Response<NewResBody>, Error = NewError>
|
L::Service: Service<Request<NewReqBody>, Response = Response<NewResBody>, Error = NewError>
|
||||||
@@ -872,7 +867,7 @@ impl<S, B, E, R> MethodRouter<S, B, E, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[doc = include_str!("../docs/method_routing/route_layer.md")]
|
#[doc = include_str!("../docs/method_routing/route_layer.md")]
|
||||||
pub fn route_layer<L, NewResBody>(self, layer: L) -> MethodRouter<S, B, E, R>
|
pub fn route_layer<L, NewResBody>(self, layer: L) -> MethodRouter<S, R, B, E>
|
||||||
where
|
where
|
||||||
L: Layer<Route<B, E>>,
|
L: Layer<Route<B, E>>,
|
||||||
L::Service: Service<Request<B>, Response = Response<NewResBody>, Error = E>
|
L::Service: Service<Request<B>, Response = Response<NewResBody>, Error = E>
|
||||||
@@ -907,7 +902,7 @@ impl<S, B, E, R> MethodRouter<S, B, E, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[doc = include_str!("../docs/method_routing/merge.md")]
|
#[doc = include_str!("../docs/method_routing/merge.md")]
|
||||||
pub fn merge(self, other: MethodRouter<S, B, E, MissingState>) -> Self {
|
pub fn merge(self, other: MethodRouter<S, MissingState, B, E>) -> Self {
|
||||||
macro_rules! merge {
|
macro_rules! merge {
|
||||||
( $first:ident, $second:ident ) => {
|
( $first:ident, $second:ident ) => {
|
||||||
match ($first, $second) {
|
match ($first, $second) {
|
||||||
@@ -1003,7 +998,7 @@ impl<S, B, E, R> MethodRouter<S, B, E, R> {
|
|||||||
/// Apply a [`HandleErrorLayer`].
|
/// Apply a [`HandleErrorLayer`].
|
||||||
///
|
///
|
||||||
/// This is a convenience method for doing `self.layer(HandleErrorLayer::new(f))`.
|
/// This is a convenience method for doing `self.layer(HandleErrorLayer::new(f))`.
|
||||||
pub fn handle_error<F, T>(self, f: F) -> MethodRouter<S, B, Infallible, R>
|
pub fn handle_error<F, T>(self, f: F) -> MethodRouter<S, R, B, Infallible>
|
||||||
where
|
where
|
||||||
F: Clone + Send + 'static,
|
F: Clone + Send + 'static,
|
||||||
HandleError<Route<B, E>, F, T>:
|
HandleError<Route<B, E>, F, T>:
|
||||||
@@ -1120,7 +1115,7 @@ fn append_allow_header(allow_header: &mut AllowHeader, method: &'static str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B, E, R> Clone for MethodRouter<S, B, E, R>
|
impl<S, B, E, R> Clone for MethodRouter<S, R, B, E>
|
||||||
where
|
where
|
||||||
S: Clone,
|
S: Clone,
|
||||||
{
|
{
|
||||||
@@ -1142,7 +1137,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B, E> Default for MethodRouter<S, B, E, MissingState>
|
impl<S, B, E> Default for MethodRouter<S, MissingState, B, E>
|
||||||
where
|
where
|
||||||
B: Send + 'static,
|
B: Send + 'static,
|
||||||
{
|
{
|
||||||
@@ -1151,7 +1146,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B, E> Service<Request<B>> for MethodRouter<S, B, E, WithState>
|
impl<S, B, E> Service<Request<B>> for MethodRouter<S, WithState, B, E>
|
||||||
where
|
where
|
||||||
B: HttpBody,
|
B: HttpBody,
|
||||||
S: Clone + Send + Sync + 'static,
|
S: Clone + Send + Sync + 'static,
|
||||||
@@ -1430,7 +1425,7 @@ mod tests {
|
|||||||
expected = "Overlapping method route. Cannot add two method routes that both handle `GET`"
|
expected = "Overlapping method route. Cannot add two method routes that both handle `GET`"
|
||||||
)]
|
)]
|
||||||
async fn handler_overlaps() {
|
async fn handler_overlaps() {
|
||||||
let _: MethodRouter<(), Body, Infallible, _> = get(ok).get(ok);
|
let _: MethodRouter<(), _, Body, Infallible> = get(ok).get(ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -1438,18 +1433,18 @@ mod tests {
|
|||||||
expected = "Overlapping method route. Cannot add two method routes that both handle `POST`"
|
expected = "Overlapping method route. Cannot add two method routes that both handle `POST`"
|
||||||
)]
|
)]
|
||||||
async fn service_overlaps() {
|
async fn service_overlaps() {
|
||||||
let _: MethodRouter<(), Body, Infallible, _> =
|
let _: MethodRouter<(), _, Body, Infallible> =
|
||||||
post_service(ok.into_service(())).post_service(ok.into_service(()));
|
post_service(ok.into_service(())).post_service(ok.into_service(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn get_head_does_not_overlap() {
|
async fn get_head_does_not_overlap() {
|
||||||
let _: MethodRouter<(), Body, Infallible, _> = get(ok).head(ok);
|
let _: MethodRouter<(), _, Body, Infallible> = get(ok).head(ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn head_get_does_not_overlap() {
|
async fn head_get_does_not_overlap() {
|
||||||
let _: MethodRouter<(), Body, Infallible, _> = head(ok).get(ok);
|
let _: MethodRouter<(), _, Body, Infallible> = head(ok).get(ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn call<S>(method: Method, svc: &mut S) -> (StatusCode, HeaderMap, String)
|
async fn call<S>(method: Method, svc: &mut S) -> (StatusCode, HeaderMap, String)
|
||||||
|
|||||||
+6
-23
@@ -7,7 +7,7 @@ use crate::{
|
|||||||
handler::{Handler, IntoExtensionService},
|
handler::{Handler, IntoExtensionService},
|
||||||
response::Response,
|
response::Response,
|
||||||
routing::strip_prefix::StripPrefix,
|
routing::strip_prefix::StripPrefix,
|
||||||
util::try_downcast,
|
util::{extract_state_assume_present, try_downcast},
|
||||||
BoxError,
|
BoxError,
|
||||||
};
|
};
|
||||||
use http::Request;
|
use http::Request;
|
||||||
@@ -207,23 +207,9 @@ where
|
|||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
.layer(MapRequestLayer::new(move |mut req: Request<_>| {
|
.layer(MapRequestLayer::new(move |mut req: Request<_>| {
|
||||||
// TODO(david): this is duplicated in `axum/src/handler/into_extension_service.rs`
|
let outer_state = extract_state_assume_present::<OuterState, _>(&req);
|
||||||
// extract into helper function
|
|
||||||
let State(outer_state) = req
|
|
||||||
.extensions()
|
|
||||||
.get::<State<OuterState>>()
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
panic!(
|
|
||||||
"no state of type `{}` was found. Please file an issue",
|
|
||||||
std::any::type_name::<State<OuterState>>()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
let inner_state = f(outer_state);
|
let inner_state = f(outer_state);
|
||||||
|
|
||||||
req.extensions_mut().insert(State(inner_state));
|
req.extensions_mut().insert(State(inner_state));
|
||||||
|
|
||||||
req
|
req
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@@ -234,7 +220,6 @@ where
|
|||||||
B: HttpBody + Send + 'static,
|
B: HttpBody + Send + 'static,
|
||||||
S: Clone,
|
S: Clone,
|
||||||
{
|
{
|
||||||
/// TODO(david): docs
|
|
||||||
pub fn with_state(state: S) -> Self {
|
pub fn with_state(state: S) -> Self {
|
||||||
Router::new().state(state)
|
Router::new().state(state)
|
||||||
}
|
}
|
||||||
@@ -244,7 +229,6 @@ impl<B> Router<(), WithState, B>
|
|||||||
where
|
where
|
||||||
B: HttpBody + Send + 'static,
|
B: HttpBody + Send + 'static,
|
||||||
{
|
{
|
||||||
/// TODO(david): docs
|
|
||||||
pub fn without_state() -> Self {
|
pub fn without_state() -> Self {
|
||||||
Router::with_state(())
|
Router::with_state(())
|
||||||
}
|
}
|
||||||
@@ -262,7 +246,7 @@ where
|
|||||||
path: &str,
|
path: &str,
|
||||||
// TODO(david): constrain this so it only accepts methods
|
// TODO(david): constrain this so it only accepts methods
|
||||||
// routers containing handlers
|
// routers containing handlers
|
||||||
method_router: MethodRouter<S, B, Infallible, MissingState>,
|
method_router: MethodRouter<S, MissingState, B, Infallible>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
validate_path_for_route(path);
|
validate_path_for_route(path);
|
||||||
|
|
||||||
@@ -301,7 +285,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO(david): docs
|
|
||||||
pub fn route_service<T>(mut self, path: &str, service: T) -> Self
|
pub fn route_service<T>(mut self, path: &str, service: T) -> Self
|
||||||
where
|
where
|
||||||
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static,
|
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static,
|
||||||
@@ -530,8 +513,9 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(david): update docs
|
||||||
#[doc = include_str!("../docs/routing/fallback.md")]
|
#[doc = include_str!("../docs/routing/fallback.md")]
|
||||||
pub fn fallback<H, T>(mut self, handler: H) -> Self
|
pub fn fallback<H, T>(self, handler: H) -> Self
|
||||||
where
|
where
|
||||||
H: Handler<S, T, B>,
|
H: Handler<S, T, B>,
|
||||||
T: 'static,
|
T: 'static,
|
||||||
@@ -540,7 +524,6 @@ where
|
|||||||
self.fallback_service(IntoExtensionService::new(handler))
|
self.fallback_service(IntoExtensionService::new(handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO(david): docs
|
|
||||||
pub fn fallback_service<T>(mut self, svc: T) -> Self
|
pub fn fallback_service<T>(mut self, svc: T) -> Self
|
||||||
where
|
where
|
||||||
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static,
|
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static,
|
||||||
@@ -786,7 +769,7 @@ impl<B, E> Fallback<B, E> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum Endpoint<S, R, B> {
|
enum Endpoint<S, R, B> {
|
||||||
MethodRouter(MethodRouter<S, B, Infallible, R>),
|
MethodRouter(MethodRouter<S, R, B, Infallible>),
|
||||||
Route(Route<B>),
|
Route(Route<B>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
use http::Request;
|
||||||
use pin_project_lite::pin_project;
|
use pin_project_lite::pin_project;
|
||||||
use std::{ops::Deref, sync::Arc};
|
use std::{ops::Deref, sync::Arc};
|
||||||
|
|
||||||
|
use crate::extract::State;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub(crate) struct PercentDecodedStr(Arc<str>);
|
pub(crate) struct PercentDecodedStr(Arc<str>);
|
||||||
|
|
||||||
@@ -54,6 +57,27 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extract the state from request extensions and panic if its not there.
|
||||||
|
///
|
||||||
|
/// This should only be called after `Router::call` or `MethodRouter::call` have been called.
|
||||||
|
pub(crate) fn extract_state_assume_present<S, B>(req: &Request<B>) -> S
|
||||||
|
where
|
||||||
|
S: Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
let State(state) = req
|
||||||
|
.extensions()
|
||||||
|
.get::<State<S>>()
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
panic!(
|
||||||
|
"no state of type `{}` was found. Please file an issue",
|
||||||
|
std::any::type_name::<State<S>>()
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
state
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_try_downcast() {
|
fn test_try_downcast() {
|
||||||
assert_eq!(try_downcast::<i32, _>(5_u32), Err(5_u32));
|
assert_eq!(try_downcast::<i32, _>(5_u32), Err(5_u32));
|
||||||
|
|||||||
Reference in New Issue
Block a user