Generic request body (#22)

Fixes #21
This commit is contained in:
David Pedersen 2021-06-19 12:50:33 +02:00 committed by GitHub
parent 6a16cd40ca
commit 356f1c8424
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 692 additions and 401 deletions

View file

@ -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

View file

@ -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"

View file

@ -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>>;

View file

@ -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`.

View file

@ -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>

View file

@ -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> {

View file

@ -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();
} }

View file

@ -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();
} }

View file

@ -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 {

View file

@ -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)?;

View file

@ -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) {

View file

@ -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()))),

View file

@ -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)

View file

@ -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;
} }

View file

@ -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)

View file

@ -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;

View file

@ -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;

View file

@ -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)
} }
} }

View file

@ -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

View file

@ -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