mirror of
https://github.com/tokio-rs/axum.git
synced 2024-10-23 17:36:39 +02:00
parent
6a16cd40ca
commit
356f1c8424
20 changed files with 692 additions and 401 deletions
11
Cargo.toml
11
Cargo.toml
|
@ -44,6 +44,7 @@ headers = { optional = true, version = "0.3" }
|
||||||
askama = "0.10.5"
|
askama = "0.10.5"
|
||||||
bb8 = "0.7.0"
|
bb8 = "0.7.0"
|
||||||
bb8-postgres = "0.7.0"
|
bb8-postgres = "0.7.0"
|
||||||
|
futures = "0.3"
|
||||||
hyper = { version = "0.14", features = ["full"] }
|
hyper = { version = "0.14", features = ["full"] }
|
||||||
reqwest = { version = "0.11", features = ["json", "stream"] }
|
reqwest = { version = "0.11", features = ["json", "stream"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
@ -66,15 +67,7 @@ features = [
|
||||||
|
|
||||||
[dev-dependencies.tower-http]
|
[dev-dependencies.tower-http]
|
||||||
version = "0.1"
|
version = "0.1"
|
||||||
features = [
|
features = ["full"]
|
||||||
"add-extension",
|
|
||||||
"auth",
|
|
||||||
"compression",
|
|
||||||
"compression-full",
|
|
||||||
"fs",
|
|
||||||
"redirect",
|
|
||||||
"trace",
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
all-features = true
|
all-features = true
|
||||||
|
|
|
@ -16,7 +16,12 @@ confidence-threshold = 0.8
|
||||||
multiple-versions = "deny"
|
multiple-versions = "deny"
|
||||||
highlight = "all"
|
highlight = "all"
|
||||||
skip-tree = []
|
skip-tree = []
|
||||||
skip = []
|
skip = [
|
||||||
|
# iri-string uses old version
|
||||||
|
# iri-string pulled in by tower-http
|
||||||
|
# PR to update tower-http is https://github.com/tower-rs/tower-http/pull/110
|
||||||
|
{ name = "nom", version = "=5.1.2" },
|
||||||
|
]
|
||||||
|
|
||||||
[sources]
|
[sources]
|
||||||
unknown-registry = "warn"
|
unknown-registry = "warn"
|
||||||
|
|
|
@ -21,7 +21,10 @@ async fn main() {
|
||||||
// run it with hyper
|
// run it with hyper
|
||||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||||
tracing::debug!("listening on {}", addr);
|
tracing::debug!("listening on {}", addr);
|
||||||
app.serve(&addr).await.unwrap();
|
hyper::Server::bind(&addr)
|
||||||
|
.serve(app.into_make_service())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConnectionPool = Pool<PostgresConnectionManager<NoTls>>;
|
type ConnectionPool = Pool<PostgresConnectionManager<NoTls>>;
|
||||||
|
|
|
@ -37,7 +37,10 @@ async fn main() {
|
||||||
// Run our application
|
// Run our application
|
||||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||||
tracing::debug!("listening on {}", addr);
|
tracing::debug!("listening on {}", addr);
|
||||||
app.serve(&addr).await.unwrap();
|
hyper::Server::bind(&addr)
|
||||||
|
.serve(app.into_make_service())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handler for `GET /users/:id`.
|
/// Handler for `GET /users/:id`.
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use awebframework::prelude::*;
|
use awebframework::prelude::*;
|
||||||
use http::Request;
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
|
@ -14,10 +13,13 @@ async fn main() {
|
||||||
// run it with hyper
|
// run it with hyper
|
||||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||||
tracing::debug!("listening on {}", addr);
|
tracing::debug!("listening on {}", addr);
|
||||||
app.serve(&addr).await.unwrap();
|
hyper::Server::bind(&addr)
|
||||||
|
.serve(app.into_make_service())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn show_form(_req: Request<Body>) -> response::Html<&'static str> {
|
async fn show_form() -> response::Html<&'static str> {
|
||||||
response::Html(
|
response::Html(
|
||||||
r#"
|
r#"
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
|
|
|
@ -12,7 +12,10 @@ async fn main() {
|
||||||
// run it
|
// run it
|
||||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||||
tracing::debug!("listening on {}", addr);
|
tracing::debug!("listening on {}", addr);
|
||||||
app.serve(&addr).await.unwrap();
|
hyper::Server::bind(&addr)
|
||||||
|
.serve(app.into_make_service())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handler() -> response::Html<&'static str> {
|
async fn handler() -> response::Html<&'static str> {
|
||||||
|
|
|
@ -58,7 +58,10 @@ async fn main() {
|
||||||
// Run our app with hyper
|
// Run our app with hyper
|
||||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||||
tracing::debug!("listening on {}", addr);
|
tracing::debug!("listening on {}", addr);
|
||||||
app.serve(&addr).await.unwrap();
|
hyper::Server::bind(&addr)
|
||||||
|
.serve(app.into_make_service())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
type SharedState = Arc<RwLock<State>>;
|
type SharedState = Arc<RwLock<State>>;
|
||||||
|
@ -98,7 +101,7 @@ async fn list_keys(Extension(state): Extension<SharedState>) -> String {
|
||||||
.join("\n")
|
.join("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn admin_routes() -> BoxRoute {
|
fn admin_routes() -> BoxRoute<hyper::Body> {
|
||||||
async fn delete_all_keys(Extension(state): Extension<SharedState>) {
|
async fn delete_all_keys(Extension(state): Extension<SharedState>) {
|
||||||
state.write().unwrap().db.clear();
|
state.write().unwrap().db.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,5 +20,8 @@ async fn main() {
|
||||||
|
|
||||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||||
tracing::debug!("listening on {}", addr);
|
tracing::debug!("listening on {}", addr);
|
||||||
app.serve(&addr).await.unwrap();
|
hyper::Server::bind(&addr)
|
||||||
|
.serve(app.into_make_service())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,10 @@ async fn main() {
|
||||||
// run it
|
// run it
|
||||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||||
tracing::debug!("listening on {}", addr);
|
tracing::debug!("listening on {}", addr);
|
||||||
app.serve(&addr).await.unwrap();
|
hyper::Server::bind(&addr)
|
||||||
|
.serve(app.into_make_service())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn greet(params: extract::UrlParamsMap) -> impl IntoResponse {
|
async fn greet(params: extract::UrlParamsMap) -> impl IntoResponse {
|
||||||
|
|
|
@ -14,7 +14,10 @@ async fn main() {
|
||||||
// run it
|
// run it
|
||||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||||
tracing::debug!("listening on {}", addr);
|
tracing::debug!("listening on {}", addr);
|
||||||
app.serve(&addr).await.unwrap();
|
hyper::Server::bind(&addr)
|
||||||
|
.serve(app.into_make_service())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handler(version: Version) {
|
async fn handler(version: Version) {
|
||||||
|
@ -29,10 +32,13 @@ enum Version {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromRequest for Version {
|
impl<B> FromRequest<B> for Version
|
||||||
|
where
|
||||||
|
B: Send,
|
||||||
|
{
|
||||||
type Rejection = Response<Body>;
|
type Rejection = Response<Body>;
|
||||||
|
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection> {
|
||||||
let params = extract::UrlParamsMap::from_request(req)
|
let params = extract::UrlParamsMap::from_request(req)
|
||||||
.await
|
.await
|
||||||
.map_err(IntoResponse::into_response)?;
|
.map_err(IntoResponse::into_response)?;
|
||||||
|
|
|
@ -51,7 +51,10 @@ async fn main() {
|
||||||
// run it with hyper
|
// run it with hyper
|
||||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||||
tracing::debug!("listening on {}", addr);
|
tracing::debug!("listening on {}", addr);
|
||||||
app.serve(&addr).await.unwrap();
|
hyper::Server::bind(&addr)
|
||||||
|
.serve(app.into_make_service())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_socket(mut socket: WebSocket) {
|
async fn handle_socket(mut socket: WebSocket) {
|
||||||
|
|
|
@ -27,7 +27,7 @@ impl BoxBody {
|
||||||
pub fn new<B>(body: B) -> Self
|
pub fn new<B>(body: B) -> Self
|
||||||
where
|
where
|
||||||
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
||||||
B::Error: Into<BoxError> + Send + Sync + 'static,
|
B::Error: Into<BoxError>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
inner: Box::pin(body.map_err(|error| BoxStdError(error.into()))),
|
inner: Box::pin(body.map_err(|error| BoxStdError(error.into()))),
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
//!
|
//!
|
||||||
//! let app = route("/users", post(create_user));
|
//! let app = route("/users", post(create_user));
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -40,10 +40,13 @@
|
||||||
//! struct ExtractUserAgent(HeaderValue);
|
//! struct ExtractUserAgent(HeaderValue);
|
||||||
//!
|
//!
|
||||||
//! #[async_trait]
|
//! #[async_trait]
|
||||||
//! impl FromRequest for ExtractUserAgent {
|
//! impl<B> FromRequest<B> for ExtractUserAgent
|
||||||
|
//! where
|
||||||
|
//! B: Send,
|
||||||
|
//! {
|
||||||
//! type Rejection = (StatusCode, &'static str);
|
//! type Rejection = (StatusCode, &'static str);
|
||||||
//!
|
//!
|
||||||
//! async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
//! async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection> {
|
||||||
//! if let Some(user_agent) = req.headers().get(USER_AGENT) {
|
//! if let Some(user_agent) = req.headers().get(USER_AGENT) {
|
||||||
//! Ok(ExtractUserAgent(user_agent.clone()))
|
//! Ok(ExtractUserAgent(user_agent.clone()))
|
||||||
//! } else {
|
//! } else {
|
||||||
|
@ -60,7 +63,7 @@
|
||||||
//!
|
//!
|
||||||
//! let app = route("/foo", get(handler));
|
//! let app = route("/foo", get(handler));
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -85,7 +88,7 @@
|
||||||
//!
|
//!
|
||||||
//! let app = route("/foo", get(handler));
|
//! let app = route("/foo", get(handler));
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -107,7 +110,7 @@
|
||||||
//!
|
//!
|
||||||
//! let app = route("/users", post(create_user));
|
//! let app = route("/users", post(create_user));
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -142,7 +145,7 @@
|
||||||
//!
|
//!
|
||||||
//! let app = route("/users", post(create_user));
|
//! let app = route("/users", post(create_user));
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -161,17 +164,30 @@
|
||||||
//!
|
//!
|
||||||
//! let app = route("/users", post(create_user));
|
//! let app = route("/users", post(create_user));
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use crate::{body::Body, response::IntoResponse, util::ByteStr};
|
use crate::{
|
||||||
|
body::{BoxBody, BoxStdError},
|
||||||
|
response::IntoResponse,
|
||||||
|
util::ByteStr,
|
||||||
|
};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use bytes::{Buf, Bytes};
|
use bytes::{Buf, Bytes};
|
||||||
|
use futures_util::stream::Stream;
|
||||||
use http::{header, HeaderMap, Method, Request, Uri, Version};
|
use http::{header, HeaderMap, Method, Request, Uri, Version};
|
||||||
|
use http_body::Body;
|
||||||
use rejection::*;
|
use rejection::*;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use std::{collections::HashMap, convert::Infallible, mem, str::FromStr};
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
convert::Infallible,
|
||||||
|
mem,
|
||||||
|
pin::Pin,
|
||||||
|
str::FromStr,
|
||||||
|
task::{Context, Poll},
|
||||||
|
};
|
||||||
|
|
||||||
pub mod rejection;
|
pub mod rejection;
|
||||||
|
|
||||||
|
@ -179,35 +195,37 @@ pub mod rejection;
|
||||||
///
|
///
|
||||||
/// See the [module docs](crate::extract) for more details.
|
/// See the [module docs](crate::extract) for more details.
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait FromRequest: Sized {
|
pub trait FromRequest<B>: Sized {
|
||||||
/// If the extractor fails it'll use this "rejection" type. A rejection is
|
/// If the extractor fails it'll use this "rejection" type. A rejection is
|
||||||
/// a kind of error that can be converted into a response.
|
/// a kind of error that can be converted into a response.
|
||||||
type Rejection: IntoResponse;
|
type Rejection: IntoResponse;
|
||||||
|
|
||||||
/// Perform the extraction.
|
/// Perform the extraction.
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection>;
|
async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<T> FromRequest for Option<T>
|
impl<T, B> FromRequest<B> for Option<T>
|
||||||
where
|
where
|
||||||
T: FromRequest,
|
T: FromRequest<B>,
|
||||||
|
B: Send,
|
||||||
{
|
{
|
||||||
type Rejection = Infallible;
|
type Rejection = Infallible;
|
||||||
|
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Option<T>, Self::Rejection> {
|
async fn from_request(req: &mut Request<B>) -> Result<Option<T>, Self::Rejection> {
|
||||||
Ok(T::from_request(req).await.ok())
|
Ok(T::from_request(req).await.ok())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<T> FromRequest for Result<T, T::Rejection>
|
impl<T, B> FromRequest<B> for Result<T, T::Rejection>
|
||||||
where
|
where
|
||||||
T: FromRequest,
|
T: FromRequest<B>,
|
||||||
|
B: Send,
|
||||||
{
|
{
|
||||||
type Rejection = Infallible;
|
type Rejection = Infallible;
|
||||||
|
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection> {
|
||||||
Ok(T::from_request(req).await)
|
Ok(T::from_request(req).await)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,6 +255,9 @@ where
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let app = route("/list_things", get(list_things));
|
/// let app = route("/list_things", get(list_things));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// If the query string cannot be parsed it will reject the request with a `400
|
/// If the query string cannot be parsed it will reject the request with a `400
|
||||||
|
@ -245,13 +266,14 @@ where
|
||||||
pub struct Query<T>(pub T);
|
pub struct Query<T>(pub T);
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<T> FromRequest for Query<T>
|
impl<T, B> FromRequest<B> for Query<T>
|
||||||
where
|
where
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
|
B: Send,
|
||||||
{
|
{
|
||||||
type Rejection = QueryRejection;
|
type Rejection = QueryRejection;
|
||||||
|
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection> {
|
||||||
let query = req.uri().query().ok_or(QueryStringMissing)?;
|
let query = req.uri().query().ok_or(QueryStringMissing)?;
|
||||||
let value = serde_urlencoded::from_str(query)
|
let value = serde_urlencoded::from_str(query)
|
||||||
.map_err(FailedToDeserializeQueryString::new::<T, _>)?;
|
.map_err(FailedToDeserializeQueryString::new::<T, _>)?;
|
||||||
|
@ -283,6 +305,9 @@ where
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let app = route("/sign_up", post(accept_form));
|
/// let app = route("/sign_up", post(accept_form));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Note that `Content-Type: multipart/form-data` requests are not supported.
|
/// Note that `Content-Type: multipart/form-data` requests are not supported.
|
||||||
|
@ -290,14 +315,17 @@ where
|
||||||
pub struct Form<T>(pub T);
|
pub struct Form<T>(pub T);
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<T> FromRequest for Form<T>
|
impl<T, B> FromRequest<B> for Form<T>
|
||||||
where
|
where
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
|
B: http_body::Body + Default + Send,
|
||||||
|
B::Data: Send,
|
||||||
|
B::Error: Into<tower::BoxError>,
|
||||||
{
|
{
|
||||||
type Rejection = FormRejection;
|
type Rejection = FormRejection;
|
||||||
|
|
||||||
#[allow(warnings)]
|
#[allow(warnings)]
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection> {
|
||||||
if !has_content_type(&req, "application/x-www-form-urlencoded") {
|
if !has_content_type(&req, "application/x-www-form-urlencoded") {
|
||||||
Err(InvalidFormContentType)?;
|
Err(InvalidFormContentType)?;
|
||||||
}
|
}
|
||||||
|
@ -343,6 +371,9 @@ where
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let app = route("/users", post(create_user));
|
/// let app = route("/users", post(create_user));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// If the query string cannot be parsed it will reject the request with a `400
|
/// If the query string cannot be parsed it will reject the request with a `400
|
||||||
|
@ -353,13 +384,16 @@ where
|
||||||
pub struct Json<T>(pub T);
|
pub struct Json<T>(pub T);
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<T> FromRequest for Json<T>
|
impl<T, B> FromRequest<B> for Json<T>
|
||||||
where
|
where
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
|
B: http_body::Body + Default + Send,
|
||||||
|
B::Data: Send,
|
||||||
|
B::Error: Into<tower::BoxError>,
|
||||||
{
|
{
|
||||||
type Rejection = JsonRejection;
|
type Rejection = JsonRejection;
|
||||||
|
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection> {
|
||||||
use bytes::Buf;
|
use bytes::Buf;
|
||||||
|
|
||||||
if has_content_type(req, "application/json") {
|
if has_content_type(req, "application/json") {
|
||||||
|
@ -419,6 +453,9 @@ fn has_content_type<B>(req: &Request<B>, expected_content_type: &str) -> bool {
|
||||||
/// // Add middleware that inserts the state into all incoming request's
|
/// // Add middleware that inserts the state into all incoming request's
|
||||||
/// // extensions.
|
/// // extensions.
|
||||||
/// .layer(AddExtensionLayer::new(state));
|
/// .layer(AddExtensionLayer::new(state));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// If the extension is missing it will reject the request with a `500 Interal
|
/// If the extension is missing it will reject the request with a `500 Interal
|
||||||
|
@ -427,13 +464,14 @@ fn has_content_type<B>(req: &Request<B>, expected_content_type: &str) -> bool {
|
||||||
pub struct Extension<T>(pub T);
|
pub struct Extension<T>(pub T);
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<T> FromRequest for Extension<T>
|
impl<T, B> FromRequest<B> for Extension<T>
|
||||||
where
|
where
|
||||||
T: Clone + Send + Sync + 'static,
|
T: Clone + Send + Sync + 'static,
|
||||||
|
B: Send,
|
||||||
{
|
{
|
||||||
type Rejection = MissingExtension;
|
type Rejection = MissingExtension;
|
||||||
|
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection> {
|
||||||
let value = req
|
let value = req
|
||||||
.extensions()
|
.extensions()
|
||||||
.get::<T>()
|
.get::<T>()
|
||||||
|
@ -445,10 +483,15 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromRequest for Bytes {
|
impl<B> FromRequest<B> for Bytes
|
||||||
|
where
|
||||||
|
B: http_body::Body + Default + Send,
|
||||||
|
B::Data: Send,
|
||||||
|
B::Error: Into<tower::BoxError>,
|
||||||
|
{
|
||||||
type Rejection = BytesRejection;
|
type Rejection = BytesRejection;
|
||||||
|
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection> {
|
||||||
let body = take_body(req)?;
|
let body = take_body(req)?;
|
||||||
|
|
||||||
let bytes = hyper::body::to_bytes(body)
|
let bytes = hyper::body::to_bytes(body)
|
||||||
|
@ -460,10 +503,15 @@ impl FromRequest for Bytes {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromRequest for String {
|
impl<B> FromRequest<B> for String
|
||||||
|
where
|
||||||
|
B: http_body::Body + Default + Send,
|
||||||
|
B::Data: Send,
|
||||||
|
B::Error: Into<tower::BoxError>,
|
||||||
|
{
|
||||||
type Rejection = StringRejection;
|
type Rejection = StringRejection;
|
||||||
|
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection> {
|
||||||
let body = take_body(req)?;
|
let body = take_body(req)?;
|
||||||
|
|
||||||
let bytes = hyper::body::to_bytes(body)
|
let bytes = hyper::body::to_bytes(body)
|
||||||
|
@ -477,20 +525,60 @@ impl FromRequest for String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
/// Extractor that extracts the request body as a [`Stream`].
|
||||||
impl FromRequest for Body {
|
///
|
||||||
type Rejection = BodyAlreadyExtracted;
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rust,no_run
|
||||||
|
/// use awebframework::prelude::*;
|
||||||
|
/// use futures::StreamExt;
|
||||||
|
///
|
||||||
|
/// async fn handler(mut stream: extract::BodyStream) {
|
||||||
|
/// while let Some(chunk) = stream.next().await {
|
||||||
|
/// // ...
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let app = route("/users", get(handler));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BodyStream(BoxBody);
|
||||||
|
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
impl Stream for BodyStream {
|
||||||
take_body(req)
|
type Item = Result<Bytes, BoxStdError>;
|
||||||
|
|
||||||
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
|
Pin::new(&mut self.0).poll_data(cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromRequest for Request<Body> {
|
impl<B> FromRequest<B> for BodyStream
|
||||||
|
where
|
||||||
|
B: http_body::Body<Data = Bytes> + Default + Send + Sync + 'static,
|
||||||
|
B::Data: Send,
|
||||||
|
B::Error: Into<tower::BoxError>,
|
||||||
|
{
|
||||||
|
type Rejection = BodyAlreadyExtracted;
|
||||||
|
|
||||||
|
async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection> {
|
||||||
|
let body = take_body(req)?;
|
||||||
|
let stream = BodyStream(BoxBody::new(body));
|
||||||
|
Ok(stream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<B> FromRequest<B> for Request<B>
|
||||||
|
where
|
||||||
|
B: Default + Send,
|
||||||
|
{
|
||||||
type Rejection = RequestAlreadyExtracted;
|
type Rejection = RequestAlreadyExtracted;
|
||||||
|
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection> {
|
||||||
struct RequestAlreadyExtractedExt;
|
struct RequestAlreadyExtractedExt;
|
||||||
|
|
||||||
if req
|
if req
|
||||||
|
@ -506,37 +594,49 @@ impl FromRequest for Request<Body> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromRequest for Method {
|
impl<B> FromRequest<B> for Method
|
||||||
|
where
|
||||||
|
B: Send,
|
||||||
|
{
|
||||||
type Rejection = Infallible;
|
type Rejection = Infallible;
|
||||||
|
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection> {
|
||||||
Ok(req.method().clone())
|
Ok(req.method().clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromRequest for Uri {
|
impl<B> FromRequest<B> for Uri
|
||||||
|
where
|
||||||
|
B: Send,
|
||||||
|
{
|
||||||
type Rejection = Infallible;
|
type Rejection = Infallible;
|
||||||
|
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection> {
|
||||||
Ok(req.uri().clone())
|
Ok(req.uri().clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromRequest for Version {
|
impl<B> FromRequest<B> for Version
|
||||||
|
where
|
||||||
|
B: Send,
|
||||||
|
{
|
||||||
type Rejection = Infallible;
|
type Rejection = Infallible;
|
||||||
|
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection> {
|
||||||
Ok(req.version())
|
Ok(req.version())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromRequest for HeaderMap {
|
impl<B> FromRequest<B> for HeaderMap
|
||||||
|
where
|
||||||
|
B: Send,
|
||||||
|
{
|
||||||
type Rejection = Infallible;
|
type Rejection = Infallible;
|
||||||
|
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection> {
|
||||||
Ok(mem::take(req.headers_mut()))
|
Ok(mem::take(req.headers_mut()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -553,6 +653,9 @@ impl FromRequest for HeaderMap {
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let app = route("/", post(handler));
|
/// let app = route("/", post(handler));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// This requires the request to have a `Content-Length` header.
|
/// This requires the request to have a `Content-Length` header.
|
||||||
|
@ -560,13 +663,14 @@ impl FromRequest for HeaderMap {
|
||||||
pub struct ContentLengthLimit<T, const N: u64>(pub T);
|
pub struct ContentLengthLimit<T, const N: u64>(pub T);
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<T, const N: u64> FromRequest for ContentLengthLimit<T, N>
|
impl<T, B, const N: u64> FromRequest<B> for ContentLengthLimit<T, N>
|
||||||
where
|
where
|
||||||
T: FromRequest,
|
T: FromRequest<B>,
|
||||||
|
B: Send,
|
||||||
{
|
{
|
||||||
type Rejection = ContentLengthLimitRejection<T::Rejection>;
|
type Rejection = ContentLengthLimitRejection<T::Rejection>;
|
||||||
|
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection> {
|
||||||
let content_length = req.headers().get(http::header::CONTENT_LENGTH).cloned();
|
let content_length = req.headers().get(http::header::CONTENT_LENGTH).cloned();
|
||||||
|
|
||||||
let content_length =
|
let content_length =
|
||||||
|
@ -604,6 +708,9 @@ where
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let app = route("/users/:id", get(users_show));
|
/// let app = route("/users/:id", get(users_show));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Note that you can only have one URL params extractor per handler. If you
|
/// Note that you can only have one URL params extractor per handler. If you
|
||||||
|
@ -627,10 +734,13 @@ impl UrlParamsMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromRequest for UrlParamsMap {
|
impl<B> FromRequest<B> for UrlParamsMap
|
||||||
|
where
|
||||||
|
B: Send,
|
||||||
|
{
|
||||||
type Rejection = MissingRouteParams;
|
type Rejection = MissingRouteParams;
|
||||||
|
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection> {
|
||||||
if let Some(params) = req
|
if let Some(params) = req
|
||||||
.extensions_mut()
|
.extensions_mut()
|
||||||
.get_mut::<Option<crate::routing::UrlParams>>()
|
.get_mut::<Option<crate::routing::UrlParams>>()
|
||||||
|
@ -664,6 +774,9 @@ impl FromRequest for UrlParamsMap {
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let app = route("/users/:user_id/team/:team_id", get(users_teams_show));
|
/// let app = route("/users/:user_id/team/:team_id", get(users_teams_show));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Note that you can only have one URL params extractor per handler. If you
|
/// Note that you can only have one URL params extractor per handler. If you
|
||||||
|
@ -676,15 +789,16 @@ macro_rules! impl_parse_url {
|
||||||
|
|
||||||
( $head:ident, $($tail:ident),* $(,)? ) => {
|
( $head:ident, $($tail:ident),* $(,)? ) => {
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<$head, $($tail,)*> FromRequest for UrlParams<($head, $($tail,)*)>
|
impl<B, $head, $($tail,)*> FromRequest<B> for UrlParams<($head, $($tail,)*)>
|
||||||
where
|
where
|
||||||
$head: FromStr + Send,
|
$head: FromStr + Send,
|
||||||
$( $tail: FromStr + Send, )*
|
$( $tail: FromStr + Send, )*
|
||||||
|
B: Send,
|
||||||
{
|
{
|
||||||
type Rejection = UrlParamsRejection;
|
type Rejection = UrlParamsRejection;
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection> {
|
||||||
let params = if let Some(params) = req
|
let params = if let Some(params) = req
|
||||||
.extensions_mut()
|
.extensions_mut()
|
||||||
.get_mut::<Option<crate::routing::UrlParams>>()
|
.get_mut::<Option<crate::routing::UrlParams>>()
|
||||||
|
@ -726,7 +840,10 @@ macro_rules! impl_parse_url {
|
||||||
|
|
||||||
impl_parse_url!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);
|
impl_parse_url!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);
|
||||||
|
|
||||||
fn take_body(req: &mut Request<Body>) -> Result<Body, BodyAlreadyExtracted> {
|
fn take_body<B>(req: &mut Request<B>) -> Result<B, BodyAlreadyExtracted>
|
||||||
|
where
|
||||||
|
B: Default,
|
||||||
|
{
|
||||||
struct BodyAlreadyExtractedExt;
|
struct BodyAlreadyExtractedExt;
|
||||||
|
|
||||||
if req
|
if req
|
||||||
|
@ -740,33 +857,6 @@ fn take_body(req: &mut Request<Body>) -> Result<Body, BodyAlreadyExtracted> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_from_request_tuple {
|
|
||||||
() => {};
|
|
||||||
|
|
||||||
( $head:ident, $($tail:ident),* $(,)? ) => {
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
#[async_trait]
|
|
||||||
impl<R, $head, $($tail,)*> FromRequest for ($head, $($tail,)*)
|
|
||||||
where
|
|
||||||
R: IntoResponse,
|
|
||||||
$head: FromRequest<Rejection = R> + Send,
|
|
||||||
$( $tail: FromRequest<Rejection = R> + Send, )*
|
|
||||||
{
|
|
||||||
type Rejection = R;
|
|
||||||
|
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
|
||||||
let $head = FromRequest::from_request(req).await?;
|
|
||||||
$( let $tail = FromRequest::from_request(req).await?; )*
|
|
||||||
Ok(($head, $($tail,)*))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_from_request_tuple!($($tail,)*);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_from_request_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);
|
|
||||||
|
|
||||||
/// Extractor that extracts a typed header value from [`headers`].
|
/// Extractor that extracts a typed header value from [`headers`].
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
@ -782,6 +872,9 @@ impl_from_request_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let app = route("/users/:user_id/team/:team_id", get(users_teams_show));
|
/// let app = route("/users/:user_id/team/:team_id", get(users_teams_show));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(feature = "headers")]
|
#[cfg(feature = "headers")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "headers")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "headers")))]
|
||||||
|
@ -791,13 +884,14 @@ pub struct TypedHeader<T>(pub T);
|
||||||
#[cfg(feature = "headers")]
|
#[cfg(feature = "headers")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "headers")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "headers")))]
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<T> FromRequest for TypedHeader<T>
|
impl<T, B> FromRequest<B> for TypedHeader<T>
|
||||||
where
|
where
|
||||||
T: headers::Header,
|
T: headers::Header,
|
||||||
|
B: Send,
|
||||||
{
|
{
|
||||||
type Rejection = rejection::TypedHeaderRejection;
|
type Rejection = rejection::TypedHeaderRejection;
|
||||||
|
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut Request<B>) -> Result<Self, Self::Rejection> {
|
||||||
let header_values = req.headers().get_all(T::name());
|
let header_values = req.headers().get_all(T::name());
|
||||||
T::decode(&mut header_values.iter())
|
T::decode(&mut header_values.iter())
|
||||||
.map(Self)
|
.map(Self)
|
||||||
|
|
|
@ -138,7 +138,7 @@ define_rejection! {
|
||||||
|
|
||||||
define_rejection! {
|
define_rejection! {
|
||||||
#[status = INTERNAL_SERVER_ERROR]
|
#[status = INTERNAL_SERVER_ERROR]
|
||||||
#[body = "Cannot have two `Request<Body>` extractors for a single handler"]
|
#[body = "Cannot have two `Request<_>` extractors for a single handler"]
|
||||||
/// Rejection type used if you try and extract the request more than once.
|
/// Rejection type used if you try and extract the request more than once.
|
||||||
pub struct RequestAlreadyExtracted;
|
pub struct RequestAlreadyExtracted;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
//! the [`extract`](crate::extract) module.
|
//! the [`extract`](crate::extract) module.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{Body, BoxBody},
|
body::BoxBody,
|
||||||
extract::FromRequest,
|
extract::FromRequest,
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
routing::{EmptyRouter, MethodFilter, RouteFuture},
|
routing::{EmptyRouter, MethodFilter, RouteFuture},
|
||||||
|
@ -71,10 +71,13 @@ pub mod future;
|
||||||
///
|
///
|
||||||
/// // All requests to `/` will go to `handler` regardless of the HTTP method.
|
/// // All requests to `/` will go to `handler` regardless of the HTTP method.
|
||||||
/// let app = route("/", any(handler));
|
/// let app = route("/", any(handler));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
pub fn any<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
|
pub fn any<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Any, handler)
|
on(MethodFilter::Any, handler)
|
||||||
}
|
}
|
||||||
|
@ -82,9 +85,9 @@ where
|
||||||
/// Route `CONNECT` requests to the given handler.
|
/// Route `CONNECT` requests to the given handler.
|
||||||
///
|
///
|
||||||
/// See [`get`] for an example.
|
/// See [`get`] for an example.
|
||||||
pub fn connect<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
|
pub fn connect<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Connect, handler)
|
on(MethodFilter::Connect, handler)
|
||||||
}
|
}
|
||||||
|
@ -92,9 +95,9 @@ where
|
||||||
/// Route `DELETE` requests to the given handler.
|
/// Route `DELETE` requests to the given handler.
|
||||||
///
|
///
|
||||||
/// See [`get`] for an example.
|
/// See [`get`] for an example.
|
||||||
pub fn delete<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
|
pub fn delete<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Delete, handler)
|
on(MethodFilter::Delete, handler)
|
||||||
}
|
}
|
||||||
|
@ -110,10 +113,13 @@ where
|
||||||
///
|
///
|
||||||
/// // Requests to `GET /` will go to `handler`.
|
/// // Requests to `GET /` will go to `handler`.
|
||||||
/// let app = route("/", get(handler));
|
/// let app = route("/", get(handler));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
|
pub fn get<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Get, handler)
|
on(MethodFilter::Get, handler)
|
||||||
}
|
}
|
||||||
|
@ -121,9 +127,9 @@ where
|
||||||
/// Route `HEAD` requests to the given handler.
|
/// Route `HEAD` requests to the given handler.
|
||||||
///
|
///
|
||||||
/// See [`get`] for an example.
|
/// See [`get`] for an example.
|
||||||
pub fn head<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
|
pub fn head<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Head, handler)
|
on(MethodFilter::Head, handler)
|
||||||
}
|
}
|
||||||
|
@ -131,9 +137,9 @@ where
|
||||||
/// Route `OPTIONS` requests to the given handler.
|
/// Route `OPTIONS` requests to the given handler.
|
||||||
///
|
///
|
||||||
/// See [`get`] for an example.
|
/// See [`get`] for an example.
|
||||||
pub fn options<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
|
pub fn options<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Options, handler)
|
on(MethodFilter::Options, handler)
|
||||||
}
|
}
|
||||||
|
@ -141,9 +147,9 @@ where
|
||||||
/// Route `PATCH` requests to the given handler.
|
/// Route `PATCH` requests to the given handler.
|
||||||
///
|
///
|
||||||
/// See [`get`] for an example.
|
/// See [`get`] for an example.
|
||||||
pub fn patch<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
|
pub fn patch<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Patch, handler)
|
on(MethodFilter::Patch, handler)
|
||||||
}
|
}
|
||||||
|
@ -151,9 +157,9 @@ where
|
||||||
/// Route `POST` requests to the given handler.
|
/// Route `POST` requests to the given handler.
|
||||||
///
|
///
|
||||||
/// See [`get`] for an example.
|
/// See [`get`] for an example.
|
||||||
pub fn post<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
|
pub fn post<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Post, handler)
|
on(MethodFilter::Post, handler)
|
||||||
}
|
}
|
||||||
|
@ -161,9 +167,9 @@ where
|
||||||
/// Route `PUT` requests to the given handler.
|
/// Route `PUT` requests to the given handler.
|
||||||
///
|
///
|
||||||
/// See [`get`] for an example.
|
/// See [`get`] for an example.
|
||||||
pub fn put<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
|
pub fn put<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Put, handler)
|
on(MethodFilter::Put, handler)
|
||||||
}
|
}
|
||||||
|
@ -171,9 +177,9 @@ where
|
||||||
/// Route `TRACE` requests to the given handler.
|
/// Route `TRACE` requests to the given handler.
|
||||||
///
|
///
|
||||||
/// See [`get`] for an example.
|
/// See [`get`] for an example.
|
||||||
pub fn trace<H, T>(handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
|
pub fn trace<H, B, T>(handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Trace, handler)
|
on(MethodFilter::Trace, handler)
|
||||||
}
|
}
|
||||||
|
@ -189,10 +195,13 @@ where
|
||||||
///
|
///
|
||||||
/// // Requests to `POST /` will go to `handler`.
|
/// // Requests to `POST /` will go to `handler`.
|
||||||
/// let app = route("/", on(MethodFilter::Post, handler));
|
/// let app = route("/", on(MethodFilter::Post, handler));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
pub fn on<H, T>(method: MethodFilter, handler: H) -> OnMethod<IntoService<H, T>, EmptyRouter>
|
pub fn on<H, B, T>(method: MethodFilter, handler: H) -> OnMethod<IntoService<H, B, T>, EmptyRouter>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
OnMethod {
|
OnMethod {
|
||||||
method,
|
method,
|
||||||
|
@ -216,14 +225,14 @@ mod sealed {
|
||||||
///
|
///
|
||||||
/// See the [module docs](crate::handler) for more details.
|
/// See the [module docs](crate::handler) for more details.
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait Handler<In>: Sized {
|
pub trait Handler<B, In>: Sized {
|
||||||
// This seals the trait. We cannot use the regular "sealed super trait" approach
|
// This seals the trait. We cannot use the regular "sealed super trait" approach
|
||||||
// due to coherence.
|
// due to coherence.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
type Sealed: sealed::HiddentTrait;
|
type Sealed: sealed::HiddentTrait;
|
||||||
|
|
||||||
/// Call the handler with the given request.
|
/// Call the handler with the given request.
|
||||||
async fn call(self, req: Request<Body>) -> Response<BoxBody>;
|
async fn call(self, req: Request<B>) -> Response<BoxBody>;
|
||||||
|
|
||||||
/// Apply a [`tower::Layer`] to the handler.
|
/// Apply a [`tower::Layer`] to the handler.
|
||||||
///
|
///
|
||||||
|
@ -248,33 +257,38 @@ pub trait Handler<In>: Sized {
|
||||||
/// async fn handler() { /* ... */ }
|
/// async fn handler() { /* ... */ }
|
||||||
///
|
///
|
||||||
/// let layered_handler = handler.layer(ConcurrencyLimitLayer::new(64));
|
/// let layered_handler = handler.layer(ConcurrencyLimitLayer::new(64));
|
||||||
|
/// let app = route("/", get(layered_handler));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// When adding middleware that might fail its required to handle those
|
/// When adding middleware that might fail its required to handle those
|
||||||
/// errors. See [`Layered::handle_error`] for more details.
|
/// errors. See [`Layered::handle_error`] for more details.
|
||||||
fn layer<L>(self, layer: L) -> Layered<L::Service, In>
|
fn layer<L>(self, layer: L) -> Layered<L::Service, In>
|
||||||
where
|
where
|
||||||
L: Layer<IntoService<Self, In>>,
|
L: Layer<IntoService<Self, B, In>>,
|
||||||
{
|
{
|
||||||
Layered::new(layer.layer(IntoService::new(self)))
|
Layered::new(layer.layer(IntoService::new(self)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the handler into a [`Service`].
|
/// Convert the handler into a [`Service`].
|
||||||
fn into_service(self) -> IntoService<Self, In> {
|
fn into_service(self) -> IntoService<Self, B, In> {
|
||||||
IntoService::new(self)
|
IntoService::new(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<F, Fut, Res> Handler<()> for F
|
impl<F, Fut, Res, B> Handler<B, ()> for F
|
||||||
where
|
where
|
||||||
F: FnOnce() -> Fut + Send + Sync,
|
F: FnOnce() -> Fut + Send + Sync,
|
||||||
Fut: Future<Output = Res> + Send,
|
Fut: Future<Output = Res> + Send,
|
||||||
Res: IntoResponse,
|
Res: IntoResponse,
|
||||||
|
B: Send + 'static,
|
||||||
{
|
{
|
||||||
type Sealed = sealed::Hidden;
|
type Sealed = sealed::Hidden;
|
||||||
|
|
||||||
async fn call(self, _req: Request<Body>) -> Response<BoxBody> {
|
async fn call(self, _req: Request<B>) -> Response<BoxBody> {
|
||||||
self().await.into_response().map(BoxBody::new)
|
self().await.into_response().map(BoxBody::new)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -285,17 +299,18 @@ macro_rules! impl_handler {
|
||||||
( $head:ident, $($tail:ident),* $(,)? ) => {
|
( $head:ident, $($tail:ident),* $(,)? ) => {
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
impl<F, Fut, Res, $head, $($tail,)*> Handler<($head, $($tail,)*)> for F
|
impl<F, Fut, B, Res, $head, $($tail,)*> Handler<B, ($head, $($tail,)*)> for F
|
||||||
where
|
where
|
||||||
F: FnOnce($head, $($tail,)*) -> Fut + Send + Sync,
|
F: FnOnce($head, $($tail,)*) -> Fut + Send + Sync,
|
||||||
Fut: Future<Output = Res> + Send,
|
Fut: Future<Output = Res> + Send,
|
||||||
|
B: Send + 'static,
|
||||||
Res: IntoResponse,
|
Res: IntoResponse,
|
||||||
$head: FromRequest + Send,
|
$head: FromRequest<B> + Send,
|
||||||
$( $tail: FromRequest + Send, )*
|
$( $tail: FromRequest<B> + Send, )*
|
||||||
{
|
{
|
||||||
type Sealed = sealed::Hidden;
|
type Sealed = sealed::Hidden;
|
||||||
|
|
||||||
async fn call(self, mut req: Request<Body>) -> Response<BoxBody> {
|
async fn call(self, mut req: Request<B>) -> Response<BoxBody> {
|
||||||
let $head = match $head::from_request(&mut req).await {
|
let $head = match $head::from_request(&mut req).await {
|
||||||
Ok(value) => value,
|
Ok(value) => value,
|
||||||
Err(rejection) => return rejection.into_response().map(BoxBody::new),
|
Err(rejection) => return rejection.into_response().map(BoxBody::new),
|
||||||
|
@ -347,17 +362,18 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<S, T, B> Handler<T> for Layered<S, T>
|
impl<S, T, ReqBody, ResBody> Handler<ReqBody, T> for Layered<S, T>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Response = Response<B>> + Send,
|
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Send,
|
||||||
S::Error: IntoResponse,
|
S::Error: IntoResponse,
|
||||||
S::Future: Send,
|
S::Future: Send,
|
||||||
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
ReqBody: Send + 'static,
|
||||||
B::Error: Into<BoxError> + Send + Sync + 'static,
|
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
||||||
|
ResBody::Error: Into<BoxError> + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
type Sealed = sealed::Hidden;
|
type Sealed = sealed::Hidden;
|
||||||
|
|
||||||
async fn call(self, req: Request<Body>) -> Response<BoxBody> {
|
async fn call(self, req: Request<ReqBody>) -> Response<BoxBody> {
|
||||||
match self
|
match self
|
||||||
.svc
|
.svc
|
||||||
.oneshot(req)
|
.oneshot(req)
|
||||||
|
@ -413,12 +429,20 @@ impl<S, T> Layered<S, T> {
|
||||||
/// )
|
/// )
|
||||||
/// }
|
/// }
|
||||||
/// });
|
/// });
|
||||||
|
///
|
||||||
|
/// let app = route("/", get(layered_handler));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// The closure can return any type that implements [`IntoResponse`].
|
/// The closure can return any type that implements [`IntoResponse`].
|
||||||
pub fn handle_error<F, B, Res>(self, f: F) -> Layered<HandleError<S, F>, T>
|
pub fn handle_error<F, ReqBody, ResBody, Res>(
|
||||||
|
self,
|
||||||
|
f: F,
|
||||||
|
) -> Layered<HandleError<S, F, ReqBody>, T>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Response = Response<B>>,
|
S: Service<Request<ReqBody>, Response = Response<ResBody>>,
|
||||||
F: FnOnce(S::Error) -> Res,
|
F: FnOnce(S::Error) -> Res,
|
||||||
Res: IntoResponse,
|
Res: IntoResponse,
|
||||||
{
|
{
|
||||||
|
@ -430,12 +454,12 @@ impl<S, T> Layered<S, T> {
|
||||||
/// An adapter that makes a [`Handler`] into a [`Service`].
|
/// An adapter that makes a [`Handler`] into a [`Service`].
|
||||||
///
|
///
|
||||||
/// Created with [`Handler::into_service`].
|
/// Created with [`Handler::into_service`].
|
||||||
pub struct IntoService<H, T> {
|
pub struct IntoService<H, B, T> {
|
||||||
handler: H,
|
handler: H,
|
||||||
_marker: PhantomData<fn() -> T>,
|
_marker: PhantomData<fn() -> (B, T)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H, T> IntoService<H, T> {
|
impl<H, B, T> IntoService<H, B, T> {
|
||||||
fn new(handler: H) -> Self {
|
fn new(handler: H) -> Self {
|
||||||
Self {
|
Self {
|
||||||
handler,
|
handler,
|
||||||
|
@ -444,7 +468,7 @@ impl<H, T> IntoService<H, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H, T> fmt::Debug for IntoService<H, T>
|
impl<H, B, T> fmt::Debug for IntoService<H, B, T>
|
||||||
where
|
where
|
||||||
H: fmt::Debug,
|
H: fmt::Debug,
|
||||||
{
|
{
|
||||||
|
@ -455,7 +479,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H, T> Clone for IntoService<H, T>
|
impl<H, B, T> Clone for IntoService<H, B, T>
|
||||||
where
|
where
|
||||||
H: Clone,
|
H: Clone,
|
||||||
{
|
{
|
||||||
|
@ -467,9 +491,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H, T> Service<Request<Body>> for IntoService<H, T>
|
impl<H, T, B> Service<Request<B>> for IntoService<H, B, T>
|
||||||
where
|
where
|
||||||
H: Handler<T> + Clone + Send + 'static,
|
H: Handler<B, T> + Clone + Send + 'static,
|
||||||
|
B: Send + 'static,
|
||||||
{
|
{
|
||||||
type Response = Response<BoxBody>;
|
type Response = Response<BoxBody>;
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
@ -482,7 +507,7 @@ where
|
||||||
Poll::Ready(Ok(()))
|
Poll::Ready(Ok(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, req: Request<Body>) -> Self::Future {
|
fn call(&mut self, req: Request<B>) -> Self::Future {
|
||||||
let handler = self.handler.clone();
|
let handler = self.handler.clone();
|
||||||
let future = Box::pin(async move {
|
let future = Box::pin(async move {
|
||||||
let res = Handler::call(handler, req).await;
|
let res = Handler::call(handler, req).await;
|
||||||
|
@ -506,9 +531,9 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// its HTTP method.
|
/// its HTTP method.
|
||||||
///
|
///
|
||||||
/// See [`OnMethod::get`] for an example.
|
/// See [`OnMethod::get`] for an example.
|
||||||
pub fn any<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
|
pub fn any<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Any, handler)
|
self.on(MethodFilter::Any, handler)
|
||||||
}
|
}
|
||||||
|
@ -516,9 +541,9 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// Chain an additional handler that will only accept `CONNECT` requests.
|
/// Chain an additional handler that will only accept `CONNECT` requests.
|
||||||
///
|
///
|
||||||
/// See [`OnMethod::get`] for an example.
|
/// See [`OnMethod::get`] for an example.
|
||||||
pub fn connect<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
|
pub fn connect<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Connect, handler)
|
self.on(MethodFilter::Connect, handler)
|
||||||
}
|
}
|
||||||
|
@ -526,9 +551,9 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// Chain an additional handler that will only accept `DELETE` requests.
|
/// Chain an additional handler that will only accept `DELETE` requests.
|
||||||
///
|
///
|
||||||
/// See [`OnMethod::get`] for an example.
|
/// See [`OnMethod::get`] for an example.
|
||||||
pub fn delete<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
|
pub fn delete<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Delete, handler)
|
self.on(MethodFilter::Delete, handler)
|
||||||
}
|
}
|
||||||
|
@ -547,10 +572,13 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// // Requests to `GET /` will go to `handler` and `POST /` will go to
|
/// // Requests to `GET /` will go to `handler` and `POST /` will go to
|
||||||
/// // `other_handler`.
|
/// // `other_handler`.
|
||||||
/// let app = route("/", post(handler).get(other_handler));
|
/// let app = route("/", post(handler).get(other_handler));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
|
pub fn get<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Get, handler)
|
self.on(MethodFilter::Get, handler)
|
||||||
}
|
}
|
||||||
|
@ -558,9 +586,9 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// Chain an additional handler that will only accept `HEAD` requests.
|
/// Chain an additional handler that will only accept `HEAD` requests.
|
||||||
///
|
///
|
||||||
/// See [`OnMethod::get`] for an example.
|
/// See [`OnMethod::get`] for an example.
|
||||||
pub fn head<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
|
pub fn head<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Head, handler)
|
self.on(MethodFilter::Head, handler)
|
||||||
}
|
}
|
||||||
|
@ -568,9 +596,9 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// Chain an additional handler that will only accept `OPTIONS` requests.
|
/// Chain an additional handler that will only accept `OPTIONS` requests.
|
||||||
///
|
///
|
||||||
/// See [`OnMethod::get`] for an example.
|
/// See [`OnMethod::get`] for an example.
|
||||||
pub fn options<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
|
pub fn options<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Options, handler)
|
self.on(MethodFilter::Options, handler)
|
||||||
}
|
}
|
||||||
|
@ -578,9 +606,9 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// Chain an additional handler that will only accept `PATCH` requests.
|
/// Chain an additional handler that will only accept `PATCH` requests.
|
||||||
///
|
///
|
||||||
/// See [`OnMethod::get`] for an example.
|
/// See [`OnMethod::get`] for an example.
|
||||||
pub fn patch<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
|
pub fn patch<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Patch, handler)
|
self.on(MethodFilter::Patch, handler)
|
||||||
}
|
}
|
||||||
|
@ -588,9 +616,9 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// Chain an additional handler that will only accept `POST` requests.
|
/// Chain an additional handler that will only accept `POST` requests.
|
||||||
///
|
///
|
||||||
/// See [`OnMethod::get`] for an example.
|
/// See [`OnMethod::get`] for an example.
|
||||||
pub fn post<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
|
pub fn post<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Post, handler)
|
self.on(MethodFilter::Post, handler)
|
||||||
}
|
}
|
||||||
|
@ -598,9 +626,9 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// Chain an additional handler that will only accept `PUT` requests.
|
/// Chain an additional handler that will only accept `PUT` requests.
|
||||||
///
|
///
|
||||||
/// See [`OnMethod::get`] for an example.
|
/// See [`OnMethod::get`] for an example.
|
||||||
pub fn put<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
|
pub fn put<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Put, handler)
|
self.on(MethodFilter::Put, handler)
|
||||||
}
|
}
|
||||||
|
@ -608,9 +636,9 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// Chain an additional handler that will only accept `TRACE` requests.
|
/// Chain an additional handler that will only accept `TRACE` requests.
|
||||||
///
|
///
|
||||||
/// See [`OnMethod::get`] for an example.
|
/// See [`OnMethod::get`] for an example.
|
||||||
pub fn trace<H, T>(self, handler: H) -> OnMethod<IntoService<H, T>, Self>
|
pub fn trace<H, B, T>(self, handler: H) -> OnMethod<IntoService<H, B, T>, Self>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Trace, handler)
|
self.on(MethodFilter::Trace, handler)
|
||||||
}
|
}
|
||||||
|
@ -630,10 +658,17 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// // Requests to `GET /` will go to `handler` and `DELETE /` will go to
|
/// // Requests to `GET /` will go to `handler` and `DELETE /` will go to
|
||||||
/// // `other_handler`
|
/// // `other_handler`
|
||||||
/// let app = route("/", get(handler).on(MethodFilter::Delete, other_handler));
|
/// let app = route("/", get(handler).on(MethodFilter::Delete, other_handler));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
pub fn on<H, T>(self, method: MethodFilter, handler: H) -> OnMethod<IntoService<H, T>, Self>
|
pub fn on<H, B, T>(
|
||||||
|
self,
|
||||||
|
method: MethodFilter,
|
||||||
|
handler: H,
|
||||||
|
) -> OnMethod<IntoService<H, B, T>, Self>
|
||||||
where
|
where
|
||||||
H: Handler<T>,
|
H: Handler<B, T>,
|
||||||
{
|
{
|
||||||
OnMethod {
|
OnMethod {
|
||||||
method,
|
method,
|
||||||
|
@ -643,20 +678,20 @@ impl<S, F> OnMethod<S, F> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, F> Service<Request<Body>> for OnMethod<S, F>
|
impl<S, F, B> Service<Request<B>> for OnMethod<S, F>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
S: Service<Request<B>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
||||||
F: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
F: Service<Request<B>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
type Response = Response<BoxBody>;
|
type Response = Response<BoxBody>;
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
type Future = RouteFuture<S, F>;
|
type Future = RouteFuture<S, F, B>;
|
||||||
|
|
||||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
Poll::Ready(Ok(()))
|
Poll::Ready(Ok(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, req: Request<Body>) -> Self::Future {
|
fn call(&mut self, req: Request<B>) -> Self::Future {
|
||||||
if self.method.matches(req.method()) {
|
if self.method.matches(req.method()) {
|
||||||
let fut = self.svc.clone().oneshot(req);
|
let fut = self.svc.clone().oneshot(req);
|
||||||
RouteFuture::a(fut)
|
RouteFuture::a(fut)
|
||||||
|
|
42
src/lib.rs
42
src/lib.rs
|
@ -33,8 +33,8 @@
|
||||||
//! let app = route("/", get(|| async { "Hello, World!" }));
|
//! let app = route("/", get(|| async { "Hello, World!" }));
|
||||||
//!
|
//!
|
||||||
//! // run it with hyper on localhost:3000
|
//! // run it with hyper on localhost:3000
|
||||||
//! app
|
//! hyper::Server::bind(&"0.0.0.0:3000".parse().unwrap())
|
||||||
//! .serve(&"0.0.0.0:3000".parse().unwrap())
|
//! .serve(app.into_make_service())
|
||||||
//! .await
|
//! .await
|
||||||
//! .unwrap();
|
//! .unwrap();
|
||||||
//! }
|
//! }
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
//! // `GET /foo` called
|
//! // `GET /foo` called
|
||||||
//! }
|
//! }
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -141,7 +141,7 @@
|
||||||
//! .route("/result", get(result))
|
//! .route("/result", get(result))
|
||||||
//! .route("/response", get(response));
|
//! .route("/response", get(response));
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -174,7 +174,7 @@
|
||||||
//! // ...
|
//! // ...
|
||||||
//! }
|
//! }
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -194,7 +194,7 @@
|
||||||
//! // ...
|
//! // ...
|
||||||
//! }
|
//! }
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -232,7 +232,7 @@
|
||||||
//! // ...
|
//! // ...
|
||||||
//! }
|
//! }
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -247,7 +247,7 @@
|
||||||
//! // ...
|
//! // ...
|
||||||
//! }
|
//! }
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -278,7 +278,7 @@
|
||||||
//!
|
//!
|
||||||
//! async fn handler() {}
|
//! async fn handler() {}
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -298,7 +298,7 @@
|
||||||
//!
|
//!
|
||||||
//! async fn post_foo() {}
|
//! async fn post_foo() {}
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -348,7 +348,7 @@
|
||||||
//!
|
//!
|
||||||
//! async fn handle() {}
|
//! async fn handle() {}
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -374,7 +374,7 @@
|
||||||
//!
|
//!
|
||||||
//! async fn other_handle() {}
|
//! async fn other_handle() {}
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -427,7 +427,7 @@
|
||||||
//! );
|
//! );
|
||||||
//! });
|
//! });
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -458,7 +458,7 @@
|
||||||
//! // ...
|
//! // ...
|
||||||
//! }
|
//! }
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -493,7 +493,7 @@
|
||||||
//! )
|
//! )
|
||||||
//! );
|
//! );
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -505,19 +505,19 @@
|
||||||
//! Applications can be nested by calling [`nest`](routing::nest):
|
//! Applications can be nested by calling [`nest`](routing::nest):
|
||||||
//!
|
//!
|
||||||
//! ```rust,no_run
|
//! ```rust,no_run
|
||||||
//! use awebframework::{prelude::*, routing::BoxRoute, body::BoxBody};
|
//! use awebframework::{prelude::*, routing::BoxRoute, body::{Body, BoxBody}};
|
||||||
//! use tower_http::services::ServeFile;
|
//! use tower_http::services::ServeFile;
|
||||||
//! use http::Response;
|
//! use http::Response;
|
||||||
//! use std::convert::Infallible;
|
//! use std::convert::Infallible;
|
||||||
//!
|
//!
|
||||||
//! fn api_routes() -> BoxRoute {
|
//! fn api_routes() -> BoxRoute<Body> {
|
||||||
//! route("/users", get(|_: Request<Body>| async { /* ... */ })).boxed()
|
//! route("/users", get(|_: Request<Body>| async { /* ... */ })).boxed()
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! let app = route("/", get(|_: Request<Body>| async { /* ... */ }))
|
//! let app = route("/", get(|_: Request<Body>| async { /* ... */ }))
|
||||||
//! .nest("/api", api_routes());
|
//! .nest("/api", api_routes());
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -537,7 +537,7 @@
|
||||||
//! })
|
//! })
|
||||||
//! );
|
//! );
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -686,9 +686,9 @@ pub mod prelude {
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if `description` doesn't start with `/`.
|
/// Panics if `description` doesn't start with `/`.
|
||||||
pub fn route<S>(description: &str, service: S) -> Route<S, EmptyRouter>
|
pub fn route<S, B>(description: &str, service: S) -> Route<S, EmptyRouter>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Error = Infallible> + Clone,
|
S: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
use routing::RoutingDsl;
|
use routing::RoutingDsl;
|
||||||
|
|
||||||
|
|
234
src/routing.rs
234
src/routing.rs
|
@ -6,7 +6,6 @@ use bytes::Bytes;
|
||||||
use futures_util::{future, ready};
|
use futures_util::{future, ready};
|
||||||
use http::{Method, Request, Response, StatusCode, Uri};
|
use http::{Method, Request, Response, StatusCode, Uri};
|
||||||
use http_body::Full;
|
use http_body::Full;
|
||||||
use hyper::Body;
|
|
||||||
use pin_project::pin_project;
|
use pin_project::pin_project;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -101,10 +100,13 @@ pub trait RoutingDsl: crate::sealed::Sealed + Sized {
|
||||||
/// // and `GET /foo` goes to third_handler.
|
/// // and `GET /foo` goes to third_handler.
|
||||||
/// let app = route("/", get(first_handler).post(second_handler))
|
/// let app = route("/", get(first_handler).post(second_handler))
|
||||||
/// .route("/foo", get(third_handler));
|
/// .route("/foo", get(third_handler));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
fn route<T>(self, description: &str, svc: T) -> Route<T, Self>
|
fn route<T, B>(self, description: &str, svc: T) -> Route<T, Self>
|
||||||
where
|
where
|
||||||
T: Service<Request<Body>, Error = Infallible> + Clone,
|
T: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
Route {
|
Route {
|
||||||
pattern: PathPattern::new(description),
|
pattern: PathPattern::new(description),
|
||||||
|
@ -116,9 +118,9 @@ pub trait RoutingDsl: crate::sealed::Sealed + Sized {
|
||||||
/// Nest another service inside this router at the given path.
|
/// Nest another service inside this router at the given path.
|
||||||
///
|
///
|
||||||
/// See [`nest`] for more details.
|
/// See [`nest`] for more details.
|
||||||
fn nest<T>(self, description: &str, svc: T) -> Nested<T, Self>
|
fn nest<T, B>(self, description: &str, svc: T) -> Nested<T, Self>
|
||||||
where
|
where
|
||||||
T: Service<Request<Body>, Error = Infallible> + Clone,
|
T: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
Nested {
|
Nested {
|
||||||
pattern: PathPattern::new(description),
|
pattern: PathPattern::new(description),
|
||||||
|
@ -133,7 +135,7 @@ pub trait RoutingDsl: crate::sealed::Sealed + Sized {
|
||||||
/// return them from functions:
|
/// return them from functions:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use awebframework::{routing::BoxRoute, prelude::*};
|
/// use awebframework::{routing::BoxRoute, body::Body, prelude::*};
|
||||||
///
|
///
|
||||||
/// async fn first_handler() { /* ... */ }
|
/// async fn first_handler() { /* ... */ }
|
||||||
///
|
///
|
||||||
|
@ -141,7 +143,7 @@ pub trait RoutingDsl: crate::sealed::Sealed + Sized {
|
||||||
///
|
///
|
||||||
/// async fn third_handler() { /* ... */ }
|
/// async fn third_handler() { /* ... */ }
|
||||||
///
|
///
|
||||||
/// fn app() -> BoxRoute {
|
/// fn app() -> BoxRoute<Body> {
|
||||||
/// route("/", get(first_handler).post(second_handler))
|
/// route("/", get(first_handler).post(second_handler))
|
||||||
/// .route("/foo", get(third_handler))
|
/// .route("/foo", get(third_handler))
|
||||||
/// .boxed()
|
/// .boxed()
|
||||||
|
@ -150,12 +152,16 @@ pub trait RoutingDsl: crate::sealed::Sealed + Sized {
|
||||||
///
|
///
|
||||||
/// It also helps with compile times when you have a very large number of
|
/// It also helps with compile times when you have a very large number of
|
||||||
/// routes.
|
/// routes.
|
||||||
fn boxed<B>(self) -> BoxRoute
|
fn boxed<ReqBody, ResBody>(self) -> BoxRoute<ReqBody>
|
||||||
where
|
where
|
||||||
Self: Service<Request<Body>, Response = Response<B>, Error = Infallible> + Send + 'static,
|
Self: Service<Request<ReqBody>, Response = Response<ResBody>, Error = Infallible>
|
||||||
<Self as Service<Request<Body>>>::Future: Send,
|
+ Send
|
||||||
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
+ 'static,
|
||||||
B::Error: Into<BoxError> + Send + Sync + 'static,
|
<Self as Service<Request<ReqBody>>>::Future: Send,
|
||||||
|
ReqBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
||||||
|
ReqBody::Error: Into<BoxError> + Send + Sync + 'static,
|
||||||
|
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
||||||
|
ResBody::Error: Into<BoxError> + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
ServiceBuilder::new()
|
ServiceBuilder::new()
|
||||||
.layer_fn(BoxRoute)
|
.layer_fn(BoxRoute)
|
||||||
|
@ -200,7 +206,7 @@ pub trait RoutingDsl: crate::sealed::Sealed + Sized {
|
||||||
/// // wont be sent through `ConcurrencyLimit`
|
/// // wont be sent through `ConcurrencyLimit`
|
||||||
/// .route("/bar", get(third_handler));
|
/// .route("/bar", get(third_handler));
|
||||||
/// # async {
|
/// # async {
|
||||||
/// # app.serve(&"".parse().unwrap()).await.unwrap();
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
/// # };
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
@ -221,6 +227,9 @@ pub trait RoutingDsl: crate::sealed::Sealed + Sized {
|
||||||
/// .route("/foo", get(second_handler))
|
/// .route("/foo", get(second_handler))
|
||||||
/// .route("/bar", get(third_handler))
|
/// .route("/bar", get(third_handler))
|
||||||
/// .layer(TraceLayer::new_for_http());
|
/// .layer(TraceLayer::new_for_http());
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// When adding middleware that might fail its required to handle those
|
/// When adding middleware that might fail its required to handle those
|
||||||
|
@ -228,9 +237,8 @@ pub trait RoutingDsl: crate::sealed::Sealed + Sized {
|
||||||
fn layer<L>(self, layer: L) -> Layered<L::Service>
|
fn layer<L>(self, layer: L) -> Layered<L::Service>
|
||||||
where
|
where
|
||||||
L: Layer<Self>,
|
L: Layer<Self>,
|
||||||
L::Service: Service<Request<Body>> + Clone,
|
|
||||||
{
|
{
|
||||||
Layered(layer.layer(self))
|
Layered::new(layer.layer(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert this router into a [`MakeService`], that is a [`Service`] who's
|
/// Convert this router into a [`MakeService`], that is a [`Service`] who's
|
||||||
|
@ -259,52 +267,26 @@ pub trait RoutingDsl: crate::sealed::Sealed + Sized {
|
||||||
{
|
{
|
||||||
tower::make::Shared::new(self)
|
tower::make::Shared::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serve this router with [hyper] on the given address.
|
|
||||||
///
|
|
||||||
/// Uses [`hyper::server::Server`]'s default configuration. Creating a
|
|
||||||
/// [`hyper::server::Server`] manually is recommended if different
|
|
||||||
/// configuration is needed. In that case [`into_make_service`] can be used
|
|
||||||
/// to easily serve this router.
|
|
||||||
///
|
|
||||||
/// [hyper]: http://crates.io/crates/hyper
|
|
||||||
/// [`into_make_service`]: RoutingDsl::into_make_service
|
|
||||||
#[cfg(any(feature = "hyper-h1", feature = "hyper-h2"))]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "hyper-h1", feature = "hyper-h2"))))]
|
|
||||||
async fn serve<B>(self, addr: &std::net::SocketAddr) -> Result<(), hyper::Error>
|
|
||||||
where
|
|
||||||
Self: Service<Request<Body>, Response = Response<B>, Error = Infallible>
|
|
||||||
+ Clone
|
|
||||||
+ Send
|
|
||||||
+ 'static,
|
|
||||||
Self::Future: Send,
|
|
||||||
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
|
||||||
B::Error: Into<BoxError> + Send + Sync + 'static,
|
|
||||||
{
|
|
||||||
hyper::server::Server::bind(addr)
|
|
||||||
.serve(self.into_make_service())
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, F> RoutingDsl for Route<S, F> {}
|
impl<S, F> RoutingDsl for Route<S, F> {}
|
||||||
|
|
||||||
impl<S, F> crate::sealed::Sealed for Route<S, F> {}
|
impl<S, F> crate::sealed::Sealed for Route<S, F> {}
|
||||||
|
|
||||||
impl<S, F> Service<Request<Body>> for Route<S, F>
|
impl<S, F, B> Service<Request<B>> for Route<S, F>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
S: Service<Request<B>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
||||||
F: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
F: Service<Request<B>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
type Response = Response<BoxBody>;
|
type Response = Response<BoxBody>;
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
type Future = RouteFuture<S, F>;
|
type Future = RouteFuture<S, F, B>;
|
||||||
|
|
||||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
Poll::Ready(Ok(()))
|
Poll::Ready(Ok(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, mut req: Request<Body>) -> Self::Future {
|
fn call(&mut self, mut req: Request<B>) -> Self::Future {
|
||||||
if let Some(captures) = self.pattern.full_match(req.uri().path()) {
|
if let Some(captures) = self.pattern.full_match(req.uri().path()) {
|
||||||
insert_url_params(&mut req, captures);
|
insert_url_params(&mut req, captures);
|
||||||
let fut = self.svc.clone().oneshot(req);
|
let fut = self.svc.clone().oneshot(req);
|
||||||
|
@ -319,40 +301,40 @@ where
|
||||||
/// The response future for [`Route`].
|
/// The response future for [`Route`].
|
||||||
#[pin_project]
|
#[pin_project]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RouteFuture<S, F>(#[pin] RouteFutureInner<S, F>)
|
pub struct RouteFuture<S, F, B>(#[pin] RouteFutureInner<S, F, B>)
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>>,
|
S: Service<Request<B>>,
|
||||||
F: Service<Request<Body>>;
|
F: Service<Request<B>>;
|
||||||
|
|
||||||
impl<S, F> RouteFuture<S, F>
|
impl<S, F, B> RouteFuture<S, F, B>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>>,
|
S: Service<Request<B>>,
|
||||||
F: Service<Request<Body>>,
|
F: Service<Request<B>>,
|
||||||
{
|
{
|
||||||
pub(crate) fn a(a: Oneshot<S, Request<Body>>) -> Self {
|
pub(crate) fn a(a: Oneshot<S, Request<B>>) -> Self {
|
||||||
RouteFuture(RouteFutureInner::A(a))
|
RouteFuture(RouteFutureInner::A(a))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn b(b: Oneshot<F, Request<Body>>) -> Self {
|
pub(crate) fn b(b: Oneshot<F, Request<B>>) -> Self {
|
||||||
RouteFuture(RouteFutureInner::B(b))
|
RouteFuture(RouteFutureInner::B(b))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pin_project(project = RouteFutureInnerProj)]
|
#[pin_project(project = RouteFutureInnerProj)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum RouteFutureInner<S, F>
|
enum RouteFutureInner<S, F, B>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>>,
|
S: Service<Request<B>>,
|
||||||
F: Service<Request<Body>>,
|
F: Service<Request<B>>,
|
||||||
{
|
{
|
||||||
A(#[pin] Oneshot<S, Request<Body>>),
|
A(#[pin] Oneshot<S, Request<B>>),
|
||||||
B(#[pin] Oneshot<F, Request<Body>>),
|
B(#[pin] Oneshot<F, Request<B>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, F> Future for RouteFuture<S, F>
|
impl<S, F, B> Future for RouteFuture<S, F, B>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible>,
|
S: Service<Request<B>, Response = Response<BoxBody>, Error = Infallible>,
|
||||||
F: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible>,
|
F: Service<Request<B>, Response = Response<BoxBody>, Error = Infallible>,
|
||||||
{
|
{
|
||||||
type Output = Result<Response<BoxBody>, Infallible>;
|
type Output = Result<Response<BoxBody>, Infallible>;
|
||||||
|
|
||||||
|
@ -393,7 +375,7 @@ impl RoutingDsl for EmptyRouter {}
|
||||||
|
|
||||||
impl crate::sealed::Sealed for EmptyRouter {}
|
impl crate::sealed::Sealed for EmptyRouter {}
|
||||||
|
|
||||||
impl Service<Request<Body>> for EmptyRouter {
|
impl<B> Service<Request<B>> for EmptyRouter {
|
||||||
type Response = Response<BoxBody>;
|
type Response = Response<BoxBody>;
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
type Future = EmptyRouterFuture;
|
type Future = EmptyRouterFuture;
|
||||||
|
@ -402,7 +384,7 @@ impl Service<Request<Body>> for EmptyRouter {
|
||||||
Poll::Ready(Ok(()))
|
Poll::Ready(Ok(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, _req: Request<Body>) -> Self::Future {
|
fn call(&mut self, _req: Request<B>) -> Self::Future {
|
||||||
let mut res = Response::new(BoxBody::empty());
|
let mut res = Response::new(BoxBody::empty());
|
||||||
*res.status_mut() = StatusCode::NOT_FOUND;
|
*res.status_mut() = StatusCode::NOT_FOUND;
|
||||||
EmptyRouterFuture(future::ok(res))
|
EmptyRouterFuture(future::ok(res))
|
||||||
|
@ -509,25 +491,28 @@ type Captures = Vec<(String, String)>;
|
||||||
/// A boxed route trait object.
|
/// A boxed route trait object.
|
||||||
///
|
///
|
||||||
/// See [`RoutingDsl::boxed`] for more details.
|
/// See [`RoutingDsl::boxed`] for more details.
|
||||||
#[derive(Clone)]
|
pub struct BoxRoute<B>(Buffer<BoxService<Request<B>, Response<BoxBody>, Infallible>, Request<B>>);
|
||||||
pub struct BoxRoute(
|
|
||||||
Buffer<BoxService<Request<Body>, Response<BoxBody>, Infallible>, Request<Body>>,
|
|
||||||
);
|
|
||||||
|
|
||||||
impl fmt::Debug for BoxRoute {
|
impl<B> Clone for BoxRoute<B> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self(self.0.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B> fmt::Debug for BoxRoute<B> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("BoxRoute").finish()
|
f.debug_struct("BoxRoute").finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RoutingDsl for BoxRoute {}
|
impl<B> RoutingDsl for BoxRoute<B> {}
|
||||||
|
|
||||||
impl crate::sealed::Sealed for BoxRoute {}
|
impl<B> crate::sealed::Sealed for BoxRoute<B> {}
|
||||||
|
|
||||||
impl Service<Request<Body>> for BoxRoute {
|
impl<B> Service<Request<B>> for BoxRoute<B> {
|
||||||
type Response = Response<BoxBody>;
|
type Response = Response<BoxBody>;
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
type Future = BoxRouteFuture;
|
type Future = BoxRouteFuture<B>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
|
@ -535,27 +520,25 @@ impl Service<Request<Body>> for BoxRoute {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn call(&mut self, req: Request<Body>) -> Self::Future {
|
fn call(&mut self, req: Request<B>) -> Self::Future {
|
||||||
BoxRouteFuture(self.0.clone().oneshot(req))
|
BoxRouteFuture(self.0.clone().oneshot(req))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The response future for [`BoxRoute`].
|
/// The response future for [`BoxRoute`].
|
||||||
#[pin_project]
|
#[pin_project]
|
||||||
pub struct BoxRouteFuture(#[pin] InnerFuture);
|
pub struct BoxRouteFuture<B>(#[pin] InnerFuture<B>);
|
||||||
|
|
||||||
type InnerFuture = Oneshot<
|
type InnerFuture<B> =
|
||||||
Buffer<BoxService<Request<Body>, Response<BoxBody>, Infallible>, Request<Body>>,
|
Oneshot<Buffer<BoxService<Request<B>, Response<BoxBody>, Infallible>, Request<B>>, Request<B>>;
|
||||||
Request<Body>,
|
|
||||||
>;
|
|
||||||
|
|
||||||
impl fmt::Debug for BoxRouteFuture {
|
impl<B> fmt::Debug for BoxRouteFuture<B> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("BoxRouteFuture").finish()
|
f.debug_struct("BoxRouteFuture").finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Future for BoxRouteFuture {
|
impl<B> Future for BoxRouteFuture<B> {
|
||||||
type Output = Result<Response<BoxBody>, Infallible>;
|
type Output = Result<Response<BoxBody>, Infallible>;
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
|
@ -601,12 +584,39 @@ fn handle_buffer_error(error: BoxError) -> Response<BoxBody> {
|
||||||
/// A [`Service`] created from a router by applying a Tower middleware.
|
/// A [`Service`] created from a router by applying a Tower middleware.
|
||||||
///
|
///
|
||||||
/// Created with [`RoutingDsl::layer`]. See that method for more details.
|
/// Created with [`RoutingDsl::layer`]. See that method for more details.
|
||||||
#[derive(Clone, Debug)]
|
pub struct Layered<S> {
|
||||||
pub struct Layered<S>(S);
|
inner: S,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> Layered<S> {
|
||||||
|
fn new(inner: S) -> Self {
|
||||||
|
Self { inner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> Clone for Layered<S>
|
||||||
|
where
|
||||||
|
S: Clone,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self::new(self.inner.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> fmt::Debug for Layered<S>
|
||||||
|
where
|
||||||
|
S: fmt::Debug,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("Layered")
|
||||||
|
.field("inner", &self.inner)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S> RoutingDsl for Layered<S> {}
|
impl<S> RoutingDsl for Layered<S> {}
|
||||||
|
|
||||||
impl<B> crate::sealed::Sealed for Layered<B> {}
|
impl<S> crate::sealed::Sealed for Layered<S> {}
|
||||||
|
|
||||||
impl<S> Layered<S> {
|
impl<S> Layered<S> {
|
||||||
/// Create a new [`Layered`] service where errors will be handled using the
|
/// Create a new [`Layered`] service where errors will be handled using the
|
||||||
|
@ -627,11 +637,11 @@ impl<S> Layered<S> {
|
||||||
/// async fn handler() { /* ... */ }
|
/// async fn handler() { /* ... */ }
|
||||||
///
|
///
|
||||||
/// // `Timeout` will fail with `BoxError` if the timeout elapses...
|
/// // `Timeout` will fail with `BoxError` if the timeout elapses...
|
||||||
/// let layered_handler = route("/", get(handler))
|
/// let layered_app = route("/", get(handler))
|
||||||
/// .layer(TimeoutLayer::new(Duration::from_secs(30)));
|
/// .layer(TimeoutLayer::new(Duration::from_secs(30)));
|
||||||
///
|
///
|
||||||
/// // ...so we must handle that error
|
/// // ...so we must handle that error
|
||||||
/// let layered_handler = layered_handler.handle_error(|error: BoxError| {
|
/// let with_errors_handled = layered_app.handle_error(|error: BoxError| {
|
||||||
/// if error.is::<tower::timeout::error::Elapsed>() {
|
/// if error.is::<tower::timeout::error::Elapsed>() {
|
||||||
/// (
|
/// (
|
||||||
/// StatusCode::REQUEST_TIMEOUT,
|
/// StatusCode::REQUEST_TIMEOUT,
|
||||||
|
@ -644,37 +654,47 @@ impl<S> Layered<S> {
|
||||||
/// )
|
/// )
|
||||||
/// }
|
/// }
|
||||||
/// });
|
/// });
|
||||||
|
///
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap())
|
||||||
|
/// # .serve(with_errors_handled.into_make_service())
|
||||||
|
/// # .await
|
||||||
|
/// # .unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// The closure can return any type that implements [`IntoResponse`].
|
/// The closure can return any type that implements [`IntoResponse`].
|
||||||
pub fn handle_error<F, B, Res>(self, f: F) -> crate::service::HandleError<S, F>
|
pub fn handle_error<F, ReqBody, ResBody, Res>(
|
||||||
|
self,
|
||||||
|
f: F,
|
||||||
|
) -> crate::service::HandleError<S, F, ReqBody>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Response = Response<B>> + Clone,
|
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone,
|
||||||
F: FnOnce(S::Error) -> Res,
|
F: FnOnce(S::Error) -> Res,
|
||||||
Res: IntoResponse,
|
Res: IntoResponse,
|
||||||
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
||||||
B::Error: Into<BoxError> + Send + Sync + 'static,
|
ResBody::Error: Into<BoxError> + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
crate::service::HandleError { inner: self.0, f }
|
crate::service::HandleError::new(self.inner, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B> Service<Request<Body>> for Layered<S>
|
impl<S, R> Service<R> for Layered<S>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Response = Response<B>, Error = Infallible>,
|
S: Service<R>,
|
||||||
{
|
{
|
||||||
type Response = S::Response;
|
type Response = S::Response;
|
||||||
type Error = Infallible;
|
type Error = S::Error;
|
||||||
type Future = S::Future;
|
type Future = S::Future;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
self.0.poll_ready(cx)
|
self.inner.poll_ready(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn call(&mut self, req: Request<Body>) -> Self::Future {
|
fn call(&mut self, req: R) -> Self::Future {
|
||||||
self.0.call(req)
|
self.inner.call(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -702,7 +722,7 @@ where
|
||||||
///
|
///
|
||||||
/// let app = nest("/api", users_api).route("/careers", get(careers));
|
/// let app = nest("/api", users_api).route("/careers", get(careers));
|
||||||
/// # async {
|
/// # async {
|
||||||
/// # app.serve(&"".parse().unwrap()).await.unwrap();
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
/// # };
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
@ -723,7 +743,7 @@ where
|
||||||
///
|
///
|
||||||
/// let app = nest("/:version/api", users_api);
|
/// let app = nest("/:version/api", users_api);
|
||||||
/// # async {
|
/// # async {
|
||||||
/// # app.serve(&"".parse().unwrap()).await.unwrap();
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
/// # };
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
@ -742,16 +762,16 @@ where
|
||||||
///
|
///
|
||||||
/// let app = nest("/public", get(serve_dir_service));
|
/// let app = nest("/public", get(serve_dir_service));
|
||||||
/// # async {
|
/// # async {
|
||||||
/// # app.serve(&"".parse().unwrap()).await.unwrap();
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
/// # };
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// If necessary you can use [`RoutingDsl::boxed`] to box a group of routes
|
/// 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
|
/// making the type easier to name. This is sometimes useful when working with
|
||||||
/// `nest`.
|
/// `nest`.
|
||||||
pub fn nest<S>(description: &str, svc: S) -> Nested<S, EmptyRouter>
|
pub fn nest<S, B>(description: &str, svc: S) -> Nested<S, EmptyRouter>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Error = Infallible> + Clone,
|
S: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
Nested {
|
Nested {
|
||||||
pattern: PathPattern::new(description),
|
pattern: PathPattern::new(description),
|
||||||
|
@ -774,20 +794,20 @@ impl<S, F> RoutingDsl for Nested<S, F> {}
|
||||||
|
|
||||||
impl<S, F> crate::sealed::Sealed for Nested<S, F> {}
|
impl<S, F> crate::sealed::Sealed for Nested<S, F> {}
|
||||||
|
|
||||||
impl<S, F> Service<Request<Body>> for Nested<S, F>
|
impl<S, F, B> Service<Request<B>> for Nested<S, F>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
S: Service<Request<B>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
||||||
F: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
F: Service<Request<B>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
type Response = Response<BoxBody>;
|
type Response = Response<BoxBody>;
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
type Future = RouteFuture<S, F>;
|
type Future = RouteFuture<S, F, B>;
|
||||||
|
|
||||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
Poll::Ready(Ok(()))
|
Poll::Ready(Ok(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, mut req: Request<Body>) -> Self::Future {
|
fn call(&mut self, mut req: Request<B>) -> Self::Future {
|
||||||
if let Some((prefix, captures)) = self.pattern.prefix_match(req.uri().path()) {
|
if let Some((prefix, captures)) = self.pattern.prefix_match(req.uri().path()) {
|
||||||
let without_prefix = strip_prefix(req.uri(), prefix);
|
let without_prefix = strip_prefix(req.uri(), prefix);
|
||||||
*req.uri_mut() = without_prefix;
|
*req.uri_mut() = without_prefix;
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
//! let app = route("/old", service::get(redirect_service))
|
//! let app = route("/old", service::get(redirect_service))
|
||||||
//! .route("/new", handler::get(handler));
|
//! .route("/new", handler::get(handler));
|
||||||
//! # async {
|
//! # async {
|
||||||
//! # app.serve(&"".parse().unwrap()).await.unwrap();
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
//! # };
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -70,6 +70,9 @@
|
||||||
//! let app = ServiceBuilder::new()
|
//! let app = ServiceBuilder::new()
|
||||||
//! .layer(some_backpressure_sensitive_middleware)
|
//! .layer(some_backpressure_sensitive_middleware)
|
||||||
//! .service(app);
|
//! .service(app);
|
||||||
|
//! # async {
|
||||||
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! However when applying middleware around your whole application in this way
|
//! However when applying middleware around your whole application in this way
|
||||||
|
@ -84,7 +87,7 @@
|
||||||
//! [load shed]: tower::load_shed
|
//! [load shed]: tower::load_shed
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{Body, BoxBody},
|
body::BoxBody,
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
routing::{EmptyRouter, MethodFilter, RouteFuture},
|
routing::{EmptyRouter, MethodFilter, RouteFuture},
|
||||||
};
|
};
|
||||||
|
@ -96,6 +99,7 @@ use std::{
|
||||||
convert::Infallible,
|
convert::Infallible,
|
||||||
fmt,
|
fmt,
|
||||||
future::Future,
|
future::Future,
|
||||||
|
marker::PhantomData,
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
};
|
};
|
||||||
use tower::{util::Oneshot, BoxError, Service, ServiceExt as _};
|
use tower::{util::Oneshot, BoxError, Service, ServiceExt as _};
|
||||||
|
@ -105,9 +109,9 @@ pub mod future;
|
||||||
/// Route requests to the given service regardless of the HTTP method.
|
/// Route requests to the given service regardless of the HTTP method.
|
||||||
///
|
///
|
||||||
/// See [`get`] for an example.
|
/// See [`get`] for an example.
|
||||||
pub fn any<S>(svc: S) -> OnMethod<BoxResponseBody<S>, EmptyRouter>
|
pub fn any<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Error = Infallible> + Clone,
|
S: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Any, svc)
|
on(MethodFilter::Any, svc)
|
||||||
}
|
}
|
||||||
|
@ -115,9 +119,9 @@ where
|
||||||
/// Route `CONNECT` requests to the given service.
|
/// Route `CONNECT` requests to the given service.
|
||||||
///
|
///
|
||||||
/// See [`get`] for an example.
|
/// See [`get`] for an example.
|
||||||
pub fn connect<S>(svc: S) -> OnMethod<BoxResponseBody<S>, EmptyRouter>
|
pub fn connect<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Error = Infallible> + Clone,
|
S: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Connect, svc)
|
on(MethodFilter::Connect, svc)
|
||||||
}
|
}
|
||||||
|
@ -125,9 +129,9 @@ where
|
||||||
/// Route `DELETE` requests to the given service.
|
/// Route `DELETE` requests to the given service.
|
||||||
///
|
///
|
||||||
/// See [`get`] for an example.
|
/// See [`get`] for an example.
|
||||||
pub fn delete<S>(svc: S) -> OnMethod<BoxResponseBody<S>, EmptyRouter>
|
pub fn delete<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Error = Infallible> + Clone,
|
S: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Delete, svc)
|
on(MethodFilter::Delete, svc)
|
||||||
}
|
}
|
||||||
|
@ -148,13 +152,16 @@ where
|
||||||
///
|
///
|
||||||
/// // Requests to `GET /` will go to `service`.
|
/// // Requests to `GET /` will go to `service`.
|
||||||
/// let app = route("/", service::get(service));
|
/// let app = route("/", service::get(service));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// You can only add services who cannot fail (their error type must be
|
/// You can only add services who cannot fail (their error type must be
|
||||||
/// [`Infallible`]). To gracefully handle errors see [`ServiceExt::handle_error`].
|
/// [`Infallible`]). To gracefully handle errors see [`ServiceExt::handle_error`].
|
||||||
pub fn get<S>(svc: S) -> OnMethod<BoxResponseBody<S>, EmptyRouter>
|
pub fn get<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Error = Infallible> + Clone,
|
S: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Get, svc)
|
on(MethodFilter::Get, svc)
|
||||||
}
|
}
|
||||||
|
@ -162,9 +169,9 @@ where
|
||||||
/// Route `HEAD` requests to the given service.
|
/// Route `HEAD` requests to the given service.
|
||||||
///
|
///
|
||||||
/// See [`get`] for an example.
|
/// See [`get`] for an example.
|
||||||
pub fn head<S>(svc: S) -> OnMethod<BoxResponseBody<S>, EmptyRouter>
|
pub fn head<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Error = Infallible> + Clone,
|
S: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Head, svc)
|
on(MethodFilter::Head, svc)
|
||||||
}
|
}
|
||||||
|
@ -172,9 +179,9 @@ where
|
||||||
/// Route `OPTIONS` requests to the given service.
|
/// Route `OPTIONS` requests to the given service.
|
||||||
///
|
///
|
||||||
/// See [`get`] for an example.
|
/// See [`get`] for an example.
|
||||||
pub fn options<S>(svc: S) -> OnMethod<BoxResponseBody<S>, EmptyRouter>
|
pub fn options<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Error = Infallible> + Clone,
|
S: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Options, svc)
|
on(MethodFilter::Options, svc)
|
||||||
}
|
}
|
||||||
|
@ -182,9 +189,9 @@ where
|
||||||
/// Route `PATCH` requests to the given service.
|
/// Route `PATCH` requests to the given service.
|
||||||
///
|
///
|
||||||
/// See [`get`] for an example.
|
/// See [`get`] for an example.
|
||||||
pub fn patch<S>(svc: S) -> OnMethod<BoxResponseBody<S>, EmptyRouter>
|
pub fn patch<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Error = Infallible> + Clone,
|
S: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Patch, svc)
|
on(MethodFilter::Patch, svc)
|
||||||
}
|
}
|
||||||
|
@ -192,9 +199,9 @@ where
|
||||||
/// Route `POST` requests to the given service.
|
/// Route `POST` requests to the given service.
|
||||||
///
|
///
|
||||||
/// See [`get`] for an example.
|
/// See [`get`] for an example.
|
||||||
pub fn post<S>(svc: S) -> OnMethod<BoxResponseBody<S>, EmptyRouter>
|
pub fn post<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Error = Infallible> + Clone,
|
S: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Post, svc)
|
on(MethodFilter::Post, svc)
|
||||||
}
|
}
|
||||||
|
@ -202,9 +209,9 @@ where
|
||||||
/// Route `PUT` requests to the given service.
|
/// Route `PUT` requests to the given service.
|
||||||
///
|
///
|
||||||
/// See [`get`] for an example.
|
/// See [`get`] for an example.
|
||||||
pub fn put<S>(svc: S) -> OnMethod<BoxResponseBody<S>, EmptyRouter>
|
pub fn put<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Error = Infallible> + Clone,
|
S: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Put, svc)
|
on(MethodFilter::Put, svc)
|
||||||
}
|
}
|
||||||
|
@ -212,9 +219,9 @@ where
|
||||||
/// Route `TRACE` requests to the given service.
|
/// Route `TRACE` requests to the given service.
|
||||||
///
|
///
|
||||||
/// See [`get`] for an example.
|
/// See [`get`] for an example.
|
||||||
pub fn trace<S>(svc: S) -> OnMethod<BoxResponseBody<S>, EmptyRouter>
|
pub fn trace<S, B>(svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Error = Infallible> + Clone,
|
S: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
on(MethodFilter::Trace, svc)
|
on(MethodFilter::Trace, svc)
|
||||||
}
|
}
|
||||||
|
@ -235,14 +242,20 @@ where
|
||||||
///
|
///
|
||||||
/// // Requests to `POST /` will go to `service`.
|
/// // Requests to `POST /` will go to `service`.
|
||||||
/// let app = route("/", service::on(MethodFilter::Post, service));
|
/// let app = route("/", service::on(MethodFilter::Post, service));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
pub fn on<S>(method: MethodFilter, svc: S) -> OnMethod<BoxResponseBody<S>, EmptyRouter>
|
pub fn on<S, B>(method: MethodFilter, svc: S) -> OnMethod<BoxResponseBody<S, B>, EmptyRouter>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Error = Infallible> + Clone,
|
S: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
OnMethod {
|
OnMethod {
|
||||||
method,
|
method,
|
||||||
svc: BoxResponseBody(svc),
|
svc: BoxResponseBody {
|
||||||
|
inner: svc,
|
||||||
|
_request_body: PhantomData,
|
||||||
|
},
|
||||||
fallback: EmptyRouter,
|
fallback: EmptyRouter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,9 +274,9 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// its HTTP method.
|
/// its HTTP method.
|
||||||
///
|
///
|
||||||
/// See [`OnMethod::get`] for an example.
|
/// See [`OnMethod::get`] for an example.
|
||||||
pub fn any<T>(self, svc: T) -> OnMethod<BoxResponseBody<T>, Self>
|
pub fn any<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||||
where
|
where
|
||||||
T: Service<Request<Body>, Error = Infallible> + Clone,
|
T: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Any, svc)
|
self.on(MethodFilter::Any, svc)
|
||||||
}
|
}
|
||||||
|
@ -271,9 +284,9 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// Chain an additional service that will only accept `CONNECT` requests.
|
/// Chain an additional service that will only accept `CONNECT` requests.
|
||||||
///
|
///
|
||||||
/// See [`OnMethod::get`] for an example.
|
/// See [`OnMethod::get`] for an example.
|
||||||
pub fn connect<T>(self, svc: T) -> OnMethod<BoxResponseBody<T>, Self>
|
pub fn connect<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||||
where
|
where
|
||||||
T: Service<Request<Body>, Error = Infallible> + Clone,
|
T: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Connect, svc)
|
self.on(MethodFilter::Connect, svc)
|
||||||
}
|
}
|
||||||
|
@ -281,9 +294,9 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// Chain an additional service that will only accept `DELETE` requests.
|
/// Chain an additional service that will only accept `DELETE` requests.
|
||||||
///
|
///
|
||||||
/// See [`OnMethod::get`] for an example.
|
/// See [`OnMethod::get`] for an example.
|
||||||
pub fn delete<T>(self, svc: T) -> OnMethod<BoxResponseBody<T>, Self>
|
pub fn delete<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||||
where
|
where
|
||||||
T: Service<Request<Body>, Error = Infallible> + Clone,
|
T: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Delete, svc)
|
self.on(MethodFilter::Delete, svc)
|
||||||
}
|
}
|
||||||
|
@ -309,14 +322,17 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// // Requests to `GET /` will go to `service` and `POST /` will go to
|
/// // Requests to `GET /` will go to `service` and `POST /` will go to
|
||||||
/// // `other_service`.
|
/// // `other_service`.
|
||||||
/// let app = route("/", service::post(service).get(other_service));
|
/// let app = route("/", service::post(service).get(other_service));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// You can only add services who cannot fail (their error type must be
|
/// You can only add services who cannot fail (their error type must be
|
||||||
/// [`Infallible`]). To gracefully handle errors see
|
/// [`Infallible`]). To gracefully handle errors see
|
||||||
/// [`ServiceExt::handle_error`].
|
/// [`ServiceExt::handle_error`].
|
||||||
pub fn get<T>(self, svc: T) -> OnMethod<BoxResponseBody<T>, Self>
|
pub fn get<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||||
where
|
where
|
||||||
T: Service<Request<Body>, Error = Infallible> + Clone,
|
T: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Get, svc)
|
self.on(MethodFilter::Get, svc)
|
||||||
}
|
}
|
||||||
|
@ -324,9 +340,9 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// Chain an additional service that will only accept `HEAD` requests.
|
/// Chain an additional service that will only accept `HEAD` requests.
|
||||||
///
|
///
|
||||||
/// See [`OnMethod::get`] for an example.
|
/// See [`OnMethod::get`] for an example.
|
||||||
pub fn head<T>(self, svc: T) -> OnMethod<BoxResponseBody<T>, Self>
|
pub fn head<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||||
where
|
where
|
||||||
T: Service<Request<Body>, Error = Infallible> + Clone,
|
T: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Head, svc)
|
self.on(MethodFilter::Head, svc)
|
||||||
}
|
}
|
||||||
|
@ -334,9 +350,9 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// Chain an additional service that will only accept `OPTIONS` requests.
|
/// Chain an additional service that will only accept `OPTIONS` requests.
|
||||||
///
|
///
|
||||||
/// See [`OnMethod::get`] for an example.
|
/// See [`OnMethod::get`] for an example.
|
||||||
pub fn options<T>(self, svc: T) -> OnMethod<BoxResponseBody<T>, Self>
|
pub fn options<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||||
where
|
where
|
||||||
T: Service<Request<Body>, Error = Infallible> + Clone,
|
T: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Options, svc)
|
self.on(MethodFilter::Options, svc)
|
||||||
}
|
}
|
||||||
|
@ -344,9 +360,9 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// Chain an additional service that will only accept `PATCH` requests.
|
/// Chain an additional service that will only accept `PATCH` requests.
|
||||||
///
|
///
|
||||||
/// See [`OnMethod::get`] for an example.
|
/// See [`OnMethod::get`] for an example.
|
||||||
pub fn patch<T>(self, svc: T) -> OnMethod<BoxResponseBody<T>, Self>
|
pub fn patch<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||||
where
|
where
|
||||||
T: Service<Request<Body>, Error = Infallible> + Clone,
|
T: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Patch, svc)
|
self.on(MethodFilter::Patch, svc)
|
||||||
}
|
}
|
||||||
|
@ -354,9 +370,9 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// Chain an additional service that will only accept `POST` requests.
|
/// Chain an additional service that will only accept `POST` requests.
|
||||||
///
|
///
|
||||||
/// See [`OnMethod::get`] for an example.
|
/// See [`OnMethod::get`] for an example.
|
||||||
pub fn post<T>(self, svc: T) -> OnMethod<BoxResponseBody<T>, Self>
|
pub fn post<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||||
where
|
where
|
||||||
T: Service<Request<Body>, Error = Infallible> + Clone,
|
T: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Post, svc)
|
self.on(MethodFilter::Post, svc)
|
||||||
}
|
}
|
||||||
|
@ -364,9 +380,9 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// Chain an additional service that will only accept `PUT` requests.
|
/// Chain an additional service that will only accept `PUT` requests.
|
||||||
///
|
///
|
||||||
/// See [`OnMethod::get`] for an example.
|
/// See [`OnMethod::get`] for an example.
|
||||||
pub fn put<T>(self, svc: T) -> OnMethod<BoxResponseBody<T>, Self>
|
pub fn put<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||||
where
|
where
|
||||||
T: Service<Request<Body>, Error = Infallible> + Clone,
|
T: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Put, svc)
|
self.on(MethodFilter::Put, svc)
|
||||||
}
|
}
|
||||||
|
@ -374,9 +390,9 @@ impl<S, F> OnMethod<S, F> {
|
||||||
/// Chain an additional service that will only accept `TRACE` requests.
|
/// Chain an additional service that will only accept `TRACE` requests.
|
||||||
///
|
///
|
||||||
/// See [`OnMethod::get`] for an example.
|
/// See [`OnMethod::get`] for an example.
|
||||||
pub fn trace<T>(self, svc: T) -> OnMethod<BoxResponseBody<T>, Self>
|
pub fn trace<T, B>(self, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||||
where
|
where
|
||||||
T: Service<Request<Body>, Error = Infallible> + Clone,
|
T: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
self.on(MethodFilter::Trace, svc)
|
self.on(MethodFilter::Trace, svc)
|
||||||
}
|
}
|
||||||
|
@ -402,14 +418,20 @@ impl<S, F> OnMethod<S, F> {
|
||||||
///
|
///
|
||||||
/// // Requests to `DELETE /` will go to `service`
|
/// // Requests to `DELETE /` will go to `service`
|
||||||
/// let app = route("/", service::on(MethodFilter::Delete, service));
|
/// let app = route("/", service::on(MethodFilter::Delete, service));
|
||||||
|
/// # async {
|
||||||
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
pub fn on<T>(self, method: MethodFilter, svc: T) -> OnMethod<BoxResponseBody<T>, Self>
|
pub fn on<T, B>(self, method: MethodFilter, svc: T) -> OnMethod<BoxResponseBody<T, B>, Self>
|
||||||
where
|
where
|
||||||
T: Service<Request<Body>, Error = Infallible> + Clone,
|
T: Service<Request<B>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
OnMethod {
|
OnMethod {
|
||||||
method,
|
method,
|
||||||
svc: BoxResponseBody(svc),
|
svc: BoxResponseBody {
|
||||||
|
inner: svc,
|
||||||
|
_request_body: PhantomData,
|
||||||
|
},
|
||||||
fallback: self,
|
fallback: self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -417,20 +439,20 @@ impl<S, F> OnMethod<S, F> {
|
||||||
|
|
||||||
// this is identical to `routing::OnMethod`'s implementation. Would be nice to find a way to clean
|
// this is identical to `routing::OnMethod`'s implementation. Would be nice to find a way to clean
|
||||||
// that up, but not sure its possible.
|
// that up, but not sure its possible.
|
||||||
impl<S, F> Service<Request<Body>> for OnMethod<S, F>
|
impl<S, F, B> Service<Request<B>> for OnMethod<S, F>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
S: Service<Request<B>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
||||||
F: Service<Request<Body>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
F: Service<Request<B>, Response = Response<BoxBody>, Error = Infallible> + Clone,
|
||||||
{
|
{
|
||||||
type Response = Response<BoxBody>;
|
type Response = Response<BoxBody>;
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
type Future = RouteFuture<S, F>;
|
type Future = RouteFuture<S, F, B>;
|
||||||
|
|
||||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
Poll::Ready(Ok(()))
|
Poll::Ready(Ok(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, req: Request<Body>) -> Self::Future {
|
fn call(&mut self, req: Request<B>) -> Self::Future {
|
||||||
if self.method.matches(req.method()) {
|
if self.method.matches(req.method()) {
|
||||||
let fut = self.svc.clone().oneshot(req);
|
let fut = self.svc.clone().oneshot(req);
|
||||||
RouteFuture::a(fut)
|
RouteFuture::a(fut)
|
||||||
|
@ -447,23 +469,37 @@ where
|
||||||
/// [`handler::Layered::handle_error`](crate::handler::Layered::handle_error) or
|
/// [`handler::Layered::handle_error`](crate::handler::Layered::handle_error) or
|
||||||
/// [`routing::Layered::handle_error`](crate::routing::Layered::handle_error).
|
/// [`routing::Layered::handle_error`](crate::routing::Layered::handle_error).
|
||||||
/// See those methods for more details.
|
/// See those methods for more details.
|
||||||
#[derive(Clone)]
|
pub struct HandleError<S, F, B> {
|
||||||
pub struct HandleError<S, F> {
|
inner: S,
|
||||||
pub(crate) inner: S,
|
f: F,
|
||||||
pub(crate) f: F,
|
_marker: PhantomData<fn() -> B>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, F> crate::routing::RoutingDsl for HandleError<S, F> {}
|
impl<S, F, B> Clone for HandleError<S, F, B>
|
||||||
|
where
|
||||||
impl<S, F> crate::sealed::Sealed for HandleError<S, F> {}
|
S: Clone,
|
||||||
|
F: Clone,
|
||||||
impl<S, F> HandleError<S, F> {
|
{
|
||||||
pub(crate) fn new(inner: S, f: F) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self { inner, f }
|
Self::new(self.inner.clone(), self.f.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, F> fmt::Debug for HandleError<S, F>
|
impl<S, F, B> crate::routing::RoutingDsl for HandleError<S, F, B> {}
|
||||||
|
|
||||||
|
impl<S, F, B> crate::sealed::Sealed for HandleError<S, F, B> {}
|
||||||
|
|
||||||
|
impl<S, F, B> HandleError<S, F, B> {
|
||||||
|
pub(crate) fn new(inner: S, f: F) -> Self {
|
||||||
|
Self {
|
||||||
|
inner,
|
||||||
|
f,
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, F, B> fmt::Debug for HandleError<S, F, B>
|
||||||
where
|
where
|
||||||
S: fmt::Debug,
|
S: fmt::Debug,
|
||||||
{
|
{
|
||||||
|
@ -475,23 +511,23 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, F, B, Res> Service<Request<Body>> for HandleError<S, F>
|
impl<S, F, ReqBody, ResBody, Res> Service<Request<ReqBody>> for HandleError<S, F, ReqBody>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Response = Response<B>> + Clone,
|
S: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone,
|
||||||
F: FnOnce(S::Error) -> Res + Clone,
|
F: FnOnce(S::Error) -> Res + Clone,
|
||||||
Res: IntoResponse,
|
Res: IntoResponse,
|
||||||
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
||||||
B::Error: Into<BoxError> + Send + Sync + 'static,
|
ResBody::Error: Into<BoxError> + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
type Response = Response<BoxBody>;
|
type Response = Response<BoxBody>;
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
type Future = future::HandleErrorFuture<Oneshot<S, Request<Body>>, F>;
|
type Future = future::HandleErrorFuture<Oneshot<S, Request<ReqBody>>, F>;
|
||||||
|
|
||||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
Poll::Ready(Ok(()))
|
Poll::Ready(Ok(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, req: Request<Body>) -> Self::Future {
|
fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
|
||||||
future::HandleErrorFuture {
|
future::HandleErrorFuture {
|
||||||
f: Some(self.f.clone()),
|
f: Some(self.f.clone()),
|
||||||
inner: self.inner.clone().oneshot(req),
|
inner: self.inner.clone().oneshot(req),
|
||||||
|
@ -500,7 +536,9 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extension trait that adds additional methods to [`Service`].
|
/// Extension trait that adds additional methods to [`Service`].
|
||||||
pub trait ServiceExt<B>: Service<Request<Body>, Response = Response<B>> {
|
pub trait ServiceExt<ReqBody, ResBody>:
|
||||||
|
Service<Request<ReqBody>, Response = Response<ResBody>>
|
||||||
|
{
|
||||||
/// Handle errors from a service.
|
/// Handle errors from a service.
|
||||||
///
|
///
|
||||||
/// awebframework requires all handlers and services, that are part of the
|
/// awebframework requires all handlers and services, that are part of the
|
||||||
|
@ -533,43 +571,71 @@ pub trait ServiceExt<B>: Service<Request<Body>, Response = Response<B>> {
|
||||||
/// );
|
/// );
|
||||||
/// #
|
/// #
|
||||||
/// # async {
|
/// # async {
|
||||||
/// # app.serve(&"".parse().unwrap()).await.unwrap();
|
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
/// # };
|
/// # };
|
||||||
/// ```
|
/// ```
|
||||||
fn handle_error<F, Res>(self, f: F) -> HandleError<Self, F>
|
fn handle_error<F, Res>(self, f: F) -> HandleError<Self, F, ReqBody>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
F: FnOnce(Self::Error) -> Res,
|
F: FnOnce(Self::Error) -> Res,
|
||||||
Res: IntoResponse,
|
Res: IntoResponse,
|
||||||
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
||||||
B::Error: Into<BoxError> + Send + Sync + 'static,
|
ResBody::Error: Into<BoxError> + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
HandleError::new(self, f)
|
HandleError::new(self, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B> ServiceExt<B> for S where S: Service<Request<Body>, Response = Response<B>> {}
|
impl<S, ReqBody, ResBody> ServiceExt<ReqBody, ResBody> for S where
|
||||||
|
S: Service<Request<ReqBody>, Response = Response<ResBody>>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// A [`Service`] that boxes response bodies.
|
/// A [`Service`] that boxes response bodies.
|
||||||
#[derive(Debug, Clone)]
|
pub struct BoxResponseBody<S, B> {
|
||||||
pub struct BoxResponseBody<S>(S);
|
inner: S,
|
||||||
|
_request_body: PhantomData<fn() -> B>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<S, B> Service<Request<Body>> for BoxResponseBody<S>
|
impl<S, B> Clone for BoxResponseBody<S, B>
|
||||||
where
|
where
|
||||||
S: Service<Request<Body>, Response = Response<B>, Error = Infallible> + Clone,
|
S: Clone,
|
||||||
B: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
{
|
||||||
B::Error: Into<BoxError> + Send + Sync + 'static,
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: self.inner.clone(),
|
||||||
|
_request_body: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, B> fmt::Debug for BoxResponseBody<S, B>
|
||||||
|
where
|
||||||
|
S: fmt::Debug,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("BoxResponseBody")
|
||||||
|
.field("inner", &self.inner)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, ReqBody, ResBody> Service<Request<ReqBody>> for BoxResponseBody<S, ReqBody>
|
||||||
|
where
|
||||||
|
S: Service<Request<ReqBody>, Response = Response<ResBody>, Error = Infallible> + Clone,
|
||||||
|
ResBody: http_body::Body<Data = Bytes> + Send + Sync + 'static,
|
||||||
|
ResBody::Error: Into<BoxError> + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
type Response = Response<BoxBody>;
|
type Response = Response<BoxBody>;
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
type Future = BoxResponseBodyFuture<Oneshot<S, Request<Body>>>;
|
type Future = BoxResponseBodyFuture<Oneshot<S, Request<ReqBody>>>;
|
||||||
|
|
||||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
Poll::Ready(Ok(()))
|
Poll::Ready(Ok(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, req: Request<Body>) -> Self::Future {
|
fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
|
||||||
let fut = self.0.clone().oneshot(req);
|
let fut = self.inner.clone().oneshot(req);
|
||||||
BoxResponseBodyFuture(fut)
|
BoxResponseBodyFuture(fut)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
50
src/tests.rs
50
src/tests.rs
|
@ -8,7 +8,7 @@ use std::{
|
||||||
net::{SocketAddr, TcpListener},
|
net::{SocketAddr, TcpListener},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
use tower::{make::Shared, BoxError, Service, ServiceBuilder};
|
use tower::{make::Shared, service_fn, BoxError, Service, ServiceBuilder};
|
||||||
use tower_http::{compression::CompressionLayer, trace::TraceLayer};
|
use tower_http::{compression::CompressionLayer, trace::TraceLayer};
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
@ -329,7 +329,6 @@ async fn boxing() {
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn service_handlers() {
|
async fn service_handlers() {
|
||||||
use crate::service::ServiceExt as _;
|
use crate::service::ServiceExt as _;
|
||||||
use tower::service_fn;
|
|
||||||
use tower_http::services::ServeFile;
|
use tower_http::services::ServeFile;
|
||||||
|
|
||||||
let app = route(
|
let app = route(
|
||||||
|
@ -607,6 +606,53 @@ async fn typed_header() {
|
||||||
assert_eq!(body, "invalid HTTP header (user-agent)");
|
assert_eq!(body, "invalid HTTP header (user-agent)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn different_request_body_types() {
|
||||||
|
use http_body::{Empty, Full};
|
||||||
|
use std::convert::Infallible;
|
||||||
|
use tower_http::map_request_body::MapRequestBodyLayer;
|
||||||
|
|
||||||
|
async fn handler(body: String) -> String {
|
||||||
|
body
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn svc_handler<B>(req: Request<B>) -> Result<Response<Body>, Infallible>
|
||||||
|
where
|
||||||
|
B: http_body::Body,
|
||||||
|
B::Error: std::fmt::Debug,
|
||||||
|
{
|
||||||
|
let body = hyper::body::to_bytes(req.into_body()).await.unwrap();
|
||||||
|
Ok(Response::new(Body::from(body)))
|
||||||
|
}
|
||||||
|
|
||||||
|
let app = route("/", service::get(service_fn(svc_handler)))
|
||||||
|
.route(
|
||||||
|
"/foo",
|
||||||
|
get(handler.layer(MapRequestBodyLayer::new(|_| Full::<Bytes>::from("foo")))),
|
||||||
|
)
|
||||||
|
.layer(MapRequestBodyLayer::new(|_| Empty::<Bytes>::new()));
|
||||||
|
|
||||||
|
let addr = run_in_background(app).await;
|
||||||
|
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
|
||||||
|
let res = client
|
||||||
|
.get(format!("http://{}/", addr))
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let body = res.text().await.unwrap();
|
||||||
|
assert_eq!(body, "");
|
||||||
|
|
||||||
|
let res = client
|
||||||
|
.get(format!("http://{}/foo", addr))
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let body = res.text().await.unwrap();
|
||||||
|
assert_eq!(body, "foo");
|
||||||
|
}
|
||||||
|
|
||||||
/// Run a `tower::Service` in the background and get a URI for it.
|
/// Run a `tower::Service` in the background and get a URI for it.
|
||||||
async fn run_in_background<S, ResBody>(svc: S) -> SocketAddr
|
async fn run_in_background<S, ResBody>(svc: S) -> SocketAddr
|
||||||
where
|
where
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
//! socket.send(msg).await.unwrap();
|
//! socket.send(msg).await.unwrap();
|
||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
|
//! # async {
|
||||||
|
//! # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||||
|
//! # };
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -41,7 +44,7 @@ pub mod future;
|
||||||
/// each connection.
|
/// each connection.
|
||||||
///
|
///
|
||||||
/// See the [module docs](crate::ws) for more details.
|
/// See the [module docs](crate::ws) for more details.
|
||||||
pub fn ws<F, Fut>(callback: F) -> OnMethod<BoxResponseBody<WebSocketUpgrade<F>>, EmptyRouter>
|
pub fn ws<F, Fut, B>(callback: F) -> OnMethod<BoxResponseBody<WebSocketUpgrade<F>, B>, EmptyRouter>
|
||||||
where
|
where
|
||||||
F: FnOnce(WebSocket) -> Fut + Clone + Send + 'static,
|
F: FnOnce(WebSocket) -> Fut + Clone + Send + 'static,
|
||||||
Fut: Future<Output = ()> + Send + 'static,
|
Fut: Future<Output = ()> + Send + 'static,
|
||||||
|
@ -50,7 +53,7 @@ where
|
||||||
callback,
|
callback,
|
||||||
config: WebSocketConfig::default(),
|
config: WebSocketConfig::default(),
|
||||||
};
|
};
|
||||||
crate::service::get(svc)
|
crate::service::get::<_, B>(svc)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [`Service`] that ugprades connections to websockets and spawns a task to
|
/// [`Service`] that ugprades connections to websockets and spawns a task to
|
||||||
|
|
Loading…
Reference in a new issue