2021-06-04 01:00:48 +02:00
|
|
|
use self::body::Body;
|
2021-06-01 11:23:56 +02:00
|
|
|
use body::BoxBody;
|
2021-05-29 21:13:06 +02:00
|
|
|
use bytes::Bytes;
|
2021-05-31 10:20:07 +02:00
|
|
|
use futures_util::ready;
|
2021-06-04 01:00:48 +02:00
|
|
|
use handler::HandlerSvc;
|
|
|
|
|
use http::{Method, Request, Response};
|
2021-05-30 01:11:18 +02:00
|
|
|
use pin_project::pin_project;
|
2021-06-01 17:17:10 +02:00
|
|
|
use response::IntoResponse;
|
2021-06-04 01:00:48 +02:00
|
|
|
use routing::{EmptyRouter, OnMethod, Route};
|
2021-05-29 21:13:06 +02:00
|
|
|
use std::{
|
2021-06-01 00:34:09 +02:00
|
|
|
convert::Infallible,
|
2021-06-01 11:23:56 +02:00
|
|
|
fmt,
|
2021-05-29 21:13:06 +02:00
|
|
|
future::Future,
|
2021-05-30 01:11:18 +02:00
|
|
|
pin::Pin,
|
2021-05-29 21:13:06 +02:00
|
|
|
task::{Context, Poll},
|
|
|
|
|
};
|
2021-06-04 01:00:48 +02:00
|
|
|
use tower::{util::Oneshot, BoxError, Service, ServiceExt as _};
|
2021-05-29 21:13:06 +02:00
|
|
|
|
2021-05-30 13:24:03 +02:00
|
|
|
pub mod body;
|
|
|
|
|
pub mod extract;
|
|
|
|
|
pub mod handler;
|
|
|
|
|
pub mod response;
|
|
|
|
|
pub mod routing;
|
|
|
|
|
|
2021-06-04 01:00:48 +02:00
|
|
|
#[doc(inline)]
|
|
|
|
|
pub use self::handler::Handler;
|
|
|
|
|
#[doc(inline)]
|
|
|
|
|
pub use self::routing::AddRoute;
|
|
|
|
|
|
2021-06-01 14:52:18 +02:00
|
|
|
pub use async_trait::async_trait;
|
2021-06-01 17:17:10 +02:00
|
|
|
pub use tower_http::add_extension::{AddExtension, AddExtensionLayer};
|
2021-06-01 14:52:18 +02:00
|
|
|
|
2021-06-04 01:00:48 +02:00
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
|
|
|
pub enum MethodFilter {
|
|
|
|
|
Any,
|
|
|
|
|
Connect,
|
|
|
|
|
Delete,
|
|
|
|
|
Get,
|
|
|
|
|
Head,
|
|
|
|
|
Options,
|
|
|
|
|
Patch,
|
|
|
|
|
Post,
|
|
|
|
|
Put,
|
|
|
|
|
Trace,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl MethodFilter {
|
|
|
|
|
#[allow(clippy::match_like_matches_macro)]
|
|
|
|
|
fn matches(self, method: &Method) -> bool {
|
|
|
|
|
use MethodFilter::*;
|
|
|
|
|
|
|
|
|
|
match (self, method) {
|
|
|
|
|
(Any, _)
|
|
|
|
|
| (Connect, &Method::CONNECT)
|
|
|
|
|
| (Delete, &Method::DELETE)
|
|
|
|
|
| (Get, &Method::GET)
|
|
|
|
|
| (Head, &Method::HEAD)
|
|
|
|
|
| (Options, &Method::OPTIONS)
|
|
|
|
|
| (Patch, &Method::PATCH)
|
|
|
|
|
| (Post, &Method::POST)
|
|
|
|
|
| (Put, &Method::PUT)
|
|
|
|
|
| (Trace, &Method::TRACE) => true,
|
|
|
|
|
_ => false,
|
2021-05-29 21:13:06 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-04 01:00:48 +02:00
|
|
|
pub fn route<S>(spec: &str, svc: S) -> Route<S, EmptyRouter>
|
|
|
|
|
where
|
|
|
|
|
S: Service<Request<Body>, Error = Infallible> + Clone,
|
|
|
|
|
{
|
|
|
|
|
routing::EmptyRouter.route(spec, svc)
|
2021-05-30 04:28:24 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-04 01:00:48 +02:00
|
|
|
pub fn get<H, B, T>(handler: H) -> OnMethod<HandlerSvc<H, B, T>, EmptyRouter>
|
2021-05-30 04:28:24 +02:00
|
|
|
where
|
2021-06-04 01:00:48 +02:00
|
|
|
H: Handler<B, T>,
|
2021-05-29 21:13:06 +02:00
|
|
|
{
|
2021-06-04 01:00:48 +02:00
|
|
|
on_method(MethodFilter::Get, HandlerSvc::new(handler))
|
|
|
|
|
}
|
2021-05-29 21:13:06 +02:00
|
|
|
|
2021-06-04 01:00:48 +02:00
|
|
|
pub fn post<H, B, T>(handler: H) -> OnMethod<HandlerSvc<H, B, T>, EmptyRouter>
|
|
|
|
|
where
|
|
|
|
|
H: Handler<B, T>,
|
|
|
|
|
{
|
|
|
|
|
on_method(MethodFilter::Post, HandlerSvc::new(handler))
|
|
|
|
|
}
|
2021-05-29 21:13:06 +02:00
|
|
|
|
2021-06-04 01:00:48 +02:00
|
|
|
pub fn on_method<S>(method: MethodFilter, svc: S) -> OnMethod<S, EmptyRouter> {
|
|
|
|
|
OnMethod {
|
|
|
|
|
method,
|
|
|
|
|
svc,
|
|
|
|
|
fallback: EmptyRouter,
|
2021-06-01 00:34:09 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-04 01:00:48 +02:00
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests;
|
|
|
|
|
|
2021-06-01 00:34:09 +02:00
|
|
|
pub(crate) trait ResultExt<T> {
|
|
|
|
|
fn unwrap_infallible(self) -> T;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> ResultExt<T> for Result<T, Infallible> {
|
|
|
|
|
fn unwrap_infallible(self) -> T {
|
|
|
|
|
match self {
|
|
|
|
|
Ok(value) => value,
|
|
|
|
|
Err(err) => match err {},
|
2021-05-30 04:28:24 +02:00
|
|
|
}
|
2021-05-30 00:52:04 +02:00
|
|
|
}
|
2021-05-30 04:28:24 +02:00
|
|
|
}
|
2021-06-01 00:34:09 +02:00
|
|
|
|
|
|
|
|
// work around for `BoxError` not implementing `std::error::Error`
|
|
|
|
|
//
|
|
|
|
|
// This is currently required since tower-http's Compression middleware's body type's
|
|
|
|
|
// error only implements error when the inner error type does:
|
|
|
|
|
// https://github.com/tower-rs/tower-http/blob/master/tower-http/src/lib.rs#L310
|
|
|
|
|
//
|
|
|
|
|
// Fixing that is a breaking change to tower-http so we should wait a bit, but should
|
|
|
|
|
// totally fix it at some point.
|
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
2021-06-04 01:00:48 +02:00
|
|
|
#[error(transparent)]
|
|
|
|
|
pub struct BoxStdError(#[from] pub(crate) tower::BoxError);
|
2021-06-01 11:23:56 +02:00
|
|
|
|
|
|
|
|
pub trait ServiceExt<B>: Service<Request<Body>, Response = Response<B>> {
|
2021-06-04 01:00:48 +02:00
|
|
|
fn handle_error<F, Res>(self, f: F) -> HandleError<Self, F>
|
2021-06-01 11:23:56 +02:00
|
|
|
where
|
|
|
|
|
Self: Sized,
|
2021-06-01 17:17:10 +02:00
|
|
|
F: FnOnce(Self::Error) -> Res,
|
|
|
|
|
Res: IntoResponse<Body>,
|
2021-06-01 11:23:56 +02:00
|
|
|
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
|
|
|
|
B::Error: Into<BoxError> + Send + Sync + 'static,
|
|
|
|
|
{
|
2021-06-01 17:17:10 +02:00
|
|
|
HandleError::new(self, f)
|
2021-06-01 11:23:56 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<S, B> ServiceExt<B> for S where S: Service<Request<Body>, Response = Response<B>> {}
|
|
|
|
|
|
2021-06-04 01:00:48 +02:00
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub struct HandleError<S, F> {
|
2021-06-01 11:23:56 +02:00
|
|
|
inner: S,
|
|
|
|
|
f: F,
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-04 01:00:48 +02:00
|
|
|
impl<S, F> HandleError<S, F> {
|
2021-06-01 17:17:10 +02:00
|
|
|
pub(crate) fn new(inner: S, f: F) -> Self {
|
2021-06-04 01:00:48 +02:00
|
|
|
Self { inner, f }
|
2021-06-01 17:17:10 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-04 01:00:48 +02:00
|
|
|
impl<S, F> fmt::Debug for HandleError<S, F>
|
2021-06-01 11:23:56 +02:00
|
|
|
where
|
|
|
|
|
S: fmt::Debug,
|
|
|
|
|
{
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
f.debug_struct("HandleError")
|
|
|
|
|
.field("inner", &self.inner)
|
|
|
|
|
.field("f", &format_args!("{}", std::any::type_name::<F>()))
|
|
|
|
|
.finish()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-04 01:00:48 +02:00
|
|
|
impl<S, F, B, Res> Service<Request<Body>> for HandleError<S, F>
|
2021-06-01 11:23:56 +02:00
|
|
|
where
|
2021-06-04 01:00:48 +02:00
|
|
|
S: Service<Request<Body>, Response = Response<B>> + Clone,
|
2021-06-01 17:17:10 +02:00
|
|
|
F: FnOnce(S::Error) -> Res + Clone,
|
|
|
|
|
Res: IntoResponse<Body>,
|
2021-06-01 11:23:56 +02:00
|
|
|
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
|
|
|
|
B::Error: Into<BoxError> + Send + Sync + 'static,
|
|
|
|
|
{
|
|
|
|
|
type Response = Response<BoxBody>;
|
|
|
|
|
type Error = Infallible;
|
2021-06-04 01:00:48 +02:00
|
|
|
type Future = HandleErrorFuture<Oneshot<S, Request<Body>>, F>;
|
2021-06-01 11:23:56 +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-06-01 11:23:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn call(&mut self, req: Request<Body>) -> Self::Future {
|
|
|
|
|
HandleErrorFuture {
|
|
|
|
|
f: Some(self.f.clone()),
|
2021-06-04 01:00:48 +02:00
|
|
|
inner: self.inner.clone().oneshot(req),
|
2021-06-01 11:23:56 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[pin_project]
|
2021-06-04 01:00:48 +02:00
|
|
|
pub struct HandleErrorFuture<Fut, F> {
|
2021-06-01 11:23:56 +02:00
|
|
|
#[pin]
|
2021-06-04 01:00:48 +02:00
|
|
|
inner: Fut,
|
2021-06-01 11:23:56 +02:00
|
|
|
f: Option<F>,
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-04 01:00:48 +02:00
|
|
|
impl<Fut, F, E, B, Res> Future for HandleErrorFuture<Fut, F>
|
2021-06-01 11:23:56 +02:00
|
|
|
where
|
|
|
|
|
Fut: Future<Output = Result<Response<B>, E>>,
|
2021-06-01 17:17:10 +02:00
|
|
|
F: FnOnce(E) -> Res,
|
|
|
|
|
Res: IntoResponse<Body>,
|
2021-06-01 11:23:56 +02:00
|
|
|
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
|
|
|
|
B::Error: Into<BoxError> + Send + Sync + 'static,
|
|
|
|
|
{
|
|
|
|
|
type Output = Result<Response<BoxBody>, Infallible>;
|
|
|
|
|
|
|
|
|
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
|
|
|
let this = self.project();
|
|
|
|
|
|
2021-06-04 01:00:48 +02:00
|
|
|
match ready!(this.inner.poll(cx)) {
|
|
|
|
|
Ok(res) => Ok(res.map(BoxBody::new)).into(),
|
|
|
|
|
Err(err) => {
|
2021-06-01 11:23:56 +02:00
|
|
|
let f = this.f.take().unwrap();
|
2021-06-04 01:00:48 +02:00
|
|
|
let res = f(err).into_response();
|
2021-06-01 11:23:56 +02:00
|
|
|
Ok(res.map(BoxBody::new)).into()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|