From 03f2b8886dcc4f579eea1759fcc04b1662695c8a Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Mon, 25 Jul 2022 16:51:08 +0200 Subject: [PATCH 01/12] example --- examples/hello-world/Cargo.toml | 1 + examples/hello-world/src/main.rs | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/examples/hello-world/Cargo.toml b/examples/hello-world/Cargo.toml index 6fbee18a76..8aa0615b51 100644 --- a/examples/hello-world/Cargo.toml +++ b/examples/hello-world/Cargo.toml @@ -7,3 +7,4 @@ publish = false [dependencies] axum = { path = "../../axum" } tokio = { version = "1.0", features = ["full"] } +tower = "0.4" diff --git a/examples/hello-world/src/main.rs b/examples/hello-world/src/main.rs index ed115f6b2f..d2b357a401 100644 --- a/examples/hello-world/src/main.rs +++ b/examples/hello-world/src/main.rs @@ -4,17 +4,23 @@ //! cd examples && cargo run -p example-hello-world //! ``` -use axum::{response::Html, routing::get, Router}; +use axum::{handler::Handler, response::Html, routing::get, Router}; use std::net::SocketAddr; +use tower::layer::util::Identity; #[tokio::main] async fn main() { - // build our application with a route - let app = Router::new().route("/", get(handler)); + let app = Router::new() + .route( + "/", + get(handler.layer(Identity::new())) + .layer(Identity::new()) + .route_layer(Identity::new()), + ) + .layer(Identity::new()) + .route_layer(Identity::new()); - // run it let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - println!("listening on {}", addr); axum::Server::bind(&addr) .serve(app.into_make_service()) .await From d70eda5fa60e529b1d204afe838e4e602d044e06 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Mon, 25 Jul 2022 15:47:00 +0200 Subject: [PATCH 02/12] `MethodRouter::merge` --- axum/src/routing/method_routing.rs | 91 +++++++++++++++++------------- 1 file changed, 51 insertions(+), 40 deletions(-) diff --git a/axum/src/routing/method_routing.rs b/axum/src/routing/method_routing.rs index fc86c9ab56..a1ad85e427 100644 --- a/axum/src/routing/method_routing.rs +++ b/axum/src/routing/method_routing.rs @@ -777,19 +777,47 @@ impl MethodRouter { #[doc = include_str!("../docs/method_routing/merge.md")] pub fn merge(self, other: MethodRouter) -> Self { - macro_rules! merge { - ( $first:ident, $second:ident ) => { - match ($first, $second) { - (Some(_), Some(_)) => panic!(concat!( - "Overlapping method route. Cannot merge two method routes that both define `", - stringify!($first), - "`" - )), - (Some(svc), None) => Some(svc), - (None, Some(svc)) => Some(svc), - (None, None) => None, + // written using inner functions to generate less IR + fn merge_inner(name: &str, first: Option, second: Option) -> Option { + match (first, second) { + (Some(_), Some(_)) => panic!( + "Overlapping method route. Cannot merge two method routes that both define `{}`", name + ), + (Some(svc), None) => Some(svc), + (None, Some(svc)) => Some(svc), + (None, None) => None, + } + } + + fn merge_allow_header( + allow_header: AllowHeader, + allow_header_other: AllowHeader, + ) -> AllowHeader { + match (allow_header, allow_header_other) { + (AllowHeader::Skip, _) | (_, AllowHeader::Skip) => AllowHeader::Skip, + (AllowHeader::None, AllowHeader::None) => AllowHeader::None, + (AllowHeader::None, AllowHeader::Bytes(pick)) => AllowHeader::Bytes(pick), + (AllowHeader::Bytes(pick), AllowHeader::None) => AllowHeader::Bytes(pick), + (AllowHeader::Bytes(mut a), AllowHeader::Bytes(b)) => { + a.extend_from_slice(b","); + a.extend_from_slice(&b); + AllowHeader::Bytes(a) } - }; + } + } + + fn merge_fallback( + fallback: Fallback, + fallback_other: Fallback, + ) -> Fallback { + match (fallback, fallback_other) { + (pick @ Fallback::Default(_), Fallback::Default(_)) => pick, + (Fallback::Default(_), pick @ Fallback::Custom(_)) => pick, + (pick @ Fallback::Custom(_), Fallback::Default(_)) => pick, + (Fallback::Custom(_), Fallback::Custom(_)) => { + panic!("Cannot merge two `MethodRouter`s that both have a fallback") + } + } } let Self { @@ -820,35 +848,18 @@ impl MethodRouter { _request_body: _, } = other; - let get = merge!(get, get_other); - let head = merge!(head, head_other); - let delete = merge!(delete, delete_other); - let options = merge!(options, options_other); - let patch = merge!(patch, patch_other); - let post = merge!(post, post_other); - let put = merge!(put, put_other); - let trace = merge!(trace, trace_other); - - let fallback = match (fallback, fallback_other) { - (pick @ Fallback::Default(_), Fallback::Default(_)) => pick, - (Fallback::Default(_), pick @ Fallback::Custom(_)) => pick, - (pick @ Fallback::Custom(_), Fallback::Default(_)) => pick, - (Fallback::Custom(_), Fallback::Custom(_)) => { - panic!("Cannot merge two `MethodRouter`s that both have a fallback") - } - }; + let get = merge_inner("get", get, get_other); + let head = merge_inner("head", head, head_other); + let delete = merge_inner("delete", delete, delete_other); + let options = merge_inner("options", options, options_other); + let patch = merge_inner("patch", patch, patch_other); + let post = merge_inner("post", post, post_other); + let put = merge_inner("put", put, put_other); + let trace = merge_inner("trace", trace, trace_other); - let allow_header = match (allow_header, allow_header_other) { - (AllowHeader::Skip, _) | (_, AllowHeader::Skip) => AllowHeader::Skip, - (AllowHeader::None, AllowHeader::None) => AllowHeader::None, - (AllowHeader::None, AllowHeader::Bytes(pick)) => AllowHeader::Bytes(pick), - (AllowHeader::Bytes(pick), AllowHeader::None) => AllowHeader::Bytes(pick), - (AllowHeader::Bytes(mut a), AllowHeader::Bytes(b)) => { - a.extend_from_slice(b","); - a.extend_from_slice(&b); - AllowHeader::Bytes(a) - } - }; + let fallback = merge_fallback(fallback, fallback_other); + + let allow_header = merge_allow_header(allow_header, allow_header_other); Self { get, From afd3356789f427d96e2b968158116166be8f205f Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Mon, 25 Jul 2022 15:54:23 +0200 Subject: [PATCH 03/12] `set_content_length` and `set_allow_header` --- axum/src/routing/route.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/axum/src/routing/route.rs b/axum/src/routing/route.rs index 71ff3e0529..e116c57aa7 100644 --- a/axum/src/routing/route.rs +++ b/axum/src/routing/route.rs @@ -6,7 +6,7 @@ use axum_core::response::IntoResponse; use bytes::Bytes; use http::{ header::{self, CONTENT_LENGTH}, - HeaderValue, Request, + HeaderMap, HeaderValue, Request, }; use pin_project_lite::pin_project; use std::{ @@ -161,10 +161,10 @@ where res.extensions_mut().insert(AlreadyPassedThroughRouteFuture); } - set_allow_header(&mut res, this.allow_header); + set_allow_header(res.headers_mut(), this.allow_header); // make sure to set content-length before removing the body - set_content_length(&mut res); + set_content_length(res.size_hint(), res.headers_mut()); let res = if *this.strip_body { res.map(|_| boxed(Empty::new())) @@ -176,10 +176,10 @@ where } } -fn set_allow_header(res: &mut Response, allow_header: &mut Option) { +fn set_allow_header(headers: &mut HeaderMap, allow_header: &mut Option) { match allow_header.take() { - Some(allow_header) if !res.headers().contains_key(header::ALLOW) => { - res.headers_mut().insert( + Some(allow_header) if !headers.contains_key(header::ALLOW) => { + headers.insert( header::ALLOW, HeaderValue::from_maybe_shared(allow_header).expect("invalid `Allow` header"), ); @@ -188,15 +188,12 @@ fn set_allow_header(res: &mut Response, allow_header: &mut Option) } } -fn set_content_length(res: &mut Response) -where - B: HttpBody, -{ - if res.headers().contains_key(CONTENT_LENGTH) { +fn set_content_length(size_hint: http_body::SizeHint, headers: &mut HeaderMap) { + if headers.contains_key(CONTENT_LENGTH) { return; } - if let Some(size) = res.size_hint().exact() { + if let Some(size) = size_hint.exact() { let header_value = if size == 0 { #[allow(clippy::declare_interior_mutable_const)] const ZERO: HeaderValue = HeaderValue::from_static("0"); @@ -207,7 +204,7 @@ where HeaderValue::from_str(buffer.format(size)).unwrap() }; - res.headers_mut().insert(CONTENT_LENGTH, header_value); + headers.insert(CONTENT_LENGTH, header_value); } } From 0c80a8b5c0fd813c98185cf05cfb8535085a71a9 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Mon, 25 Jul 2022 16:13:21 +0200 Subject: [PATCH 04/12] `MethodRouter::on_service_boxed_response_body` --- axum/src/routing/method_routing.rs | 138 +++++++++++++++++++++-------- 1 file changed, 101 insertions(+), 37 deletions(-) diff --git a/axum/src/routing/method_routing.rs b/axum/src/routing/method_routing.rs index a1ad85e427..ff126db0a4 100644 --- a/axum/src/routing/method_routing.rs +++ b/axum/src/routing/method_routing.rs @@ -899,29 +899,26 @@ impl MethodRouter { S::Response: IntoResponse + 'static, S::Future: Send + 'static, { - macro_rules! set_service { - ( - $filter:ident, - $svc:ident, - $allow_header:ident, - [ - $( - ($out:ident, $variant:ident, [$($method:literal),+]) - ),+ - $(,)? - ] - ) => { - $( - if $filter.contains(MethodFilter::$variant) { - if $out.is_some() { - panic!("Overlapping method route. Cannot add two method routes that both handle `{}`", stringify!($variant)) - } - $out = $svc.clone(); - $( - append_allow_header(&mut $allow_header, $method); - )+ - } - )+ + // written using an inner function to generate less IR + fn set_service( + method_name: &str, + out: &mut Option, + svc: &T, + svc_filter: MethodFilter, + filter: MethodFilter, + allow_header: &mut AllowHeader, + methods: &[&'static str], + ) where + T: Clone, + { + if svc_filter.contains(filter) { + if out.is_some() { + panic!("Overlapping method route. Cannot add two method routes that both handle `{}`", method_name) + } + *out = Some(svc.clone()); + for method in methods { + append_allow_header(allow_header, method); + } } } @@ -939,22 +936,89 @@ impl MethodRouter { mut allow_header, _request_body: _, } = self; - let svc = Some(Route::new(svc)); - set_service!( + + let svc = Route::new(svc); + + set_service( + "GET", + &mut get, + &svc, filter, - svc, - allow_header, - [ - (get, GET, ["GET", "HEAD"]), - (head, HEAD, ["HEAD"]), - (delete, DELETE, ["DELETE"]), - (options, OPTIONS, ["OPTIONS"]), - (patch, PATCH, ["PATCH"]), - (post, POST, ["POST"]), - (put, PUT, ["PUT"]), - (trace, TRACE, ["TRACE"]), - ] + MethodFilter::GET, + &mut allow_header, + &["GET", "HEAD"], + ); + + set_service( + "HEAD", + &mut head, + &svc, + filter, + MethodFilter::HEAD, + &mut allow_header, + &["HEAD"], ); + + set_service( + "TRACE", + &mut trace, + &svc, + filter, + MethodFilter::TRACE, + &mut allow_header, + &["TRACE"], + ); + + set_service( + "PUT", + &mut put, + &svc, + filter, + MethodFilter::PUT, + &mut allow_header, + &["PUT"], + ); + + set_service( + "POST", + &mut post, + &svc, + filter, + MethodFilter::POST, + &mut allow_header, + &["POST"], + ); + + set_service( + "PATCH", + &mut patch, + &svc, + filter, + MethodFilter::PATCH, + &mut allow_header, + &["PATCH"], + ); + + set_service( + "OPTIONS", + &mut options, + &svc, + filter, + MethodFilter::OPTIONS, + &mut allow_header, + &["OPTIONS"], + ); + + set_service( + "DELETE", + &mut delete, + &svc, + filter, + MethodFilter::DELETE, + &mut allow_header, + &["DELETE"], + ); + Self { get, head, From c4fdb1059b5ee66ed3e86c8fab4b8d0203775814 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Mon, 25 Jul 2022 16:34:16 +0200 Subject: [PATCH 05/12] `Router::route` --- axum/src/routing/mod.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/axum/src/routing/mod.rs b/axum/src/routing/mod.rs index 135363971b..40e1a79429 100644 --- a/axum/src/routing/mod.rs +++ b/axum/src/routing/mod.rs @@ -126,12 +126,16 @@ where T::Response: IntoResponse, T::Future: Send + 'static, { - if path.is_empty() { - panic!("Paths must start with a `/`. Use \"/\" for root routes"); - } else if !path.starts_with('/') { - panic!("Paths must start with a `/`"); + fn validate_path(path: &str) { + if path.is_empty() { + panic!("Paths must start with a `/`. Use \"/\" for root routes"); + } else if !path.starts_with('/') { + panic!("Paths must start with a `/`"); + } } + validate_path(path); + let service = match try_downcast::, _>(service) { Ok(_) => { panic!("Invalid route: `Router::route` cannot be used with `Router`s. Use `Router::nest` instead") @@ -162,16 +166,20 @@ where Err(service) => Endpoint::Route(Route::new(service)), }; + self.set_node(path, id); + + self.routes.insert(id, service); + + self + } + + fn set_node(&mut self, path: &str, id: RouteId) { let mut node = Arc::try_unwrap(Arc::clone(&self.node)).unwrap_or_else(|node| (*node).clone()); if let Err(err) = node.insert(path, id) { self.panic_on_matchit_error(err); } self.node = Arc::new(node); - - self.routes.insert(id, service); - - self } #[doc = include_str!("../docs/routing/nest.md")] From f1a9a21de7e6ad3cc01b48c9df19e280f9333579 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Mon, 25 Jul 2022 16:37:26 +0200 Subject: [PATCH 06/12] `MethodRouter::merge` again --- axum/src/routing/method_routing.rs | 64 ++++++------------------------ 1 file changed, 12 insertions(+), 52 deletions(-) diff --git a/axum/src/routing/method_routing.rs b/axum/src/routing/method_routing.rs index ff126db0a4..336b3575c3 100644 --- a/axum/src/routing/method_routing.rs +++ b/axum/src/routing/method_routing.rs @@ -776,7 +776,7 @@ impl MethodRouter { } #[doc = include_str!("../docs/method_routing/merge.md")] - pub fn merge(self, other: MethodRouter) -> Self { + pub fn merge(mut self, other: MethodRouter) -> Self { // written using inner functions to generate less IR fn merge_inner(name: &str, first: Option, second: Option) -> Option { match (first, second) { @@ -820,60 +820,20 @@ impl MethodRouter { } } - let Self { - get, - head, - delete, - options, - patch, - post, - put, - trace, - fallback, - allow_header, - _request_body: _, - } = self; - - let Self { - get: get_other, - head: head_other, - delete: delete_other, - options: options_other, - patch: patch_other, - post: post_other, - put: put_other, - trace: trace_other, - fallback: fallback_other, - allow_header: allow_header_other, - _request_body: _, - } = other; + self.get = merge_inner("get", self.get, other.get); + self.head = merge_inner("head", self.head, other.head); + self.delete = merge_inner("delete", self.delete, other.delete); + self.options = merge_inner("options", self.options, other.options); + self.patch = merge_inner("patch", self.patch, other.patch); + self.post = merge_inner("post", self.post, other.post); + self.put = merge_inner("put", self.put, other.put); + self.trace = merge_inner("trace", self.trace, other.trace); - let get = merge_inner("get", get, get_other); - let head = merge_inner("head", head, head_other); - let delete = merge_inner("delete", delete, delete_other); - let options = merge_inner("options", options, options_other); - let patch = merge_inner("patch", patch, patch_other); - let post = merge_inner("post", post, post_other); - let put = merge_inner("put", put, put_other); - let trace = merge_inner("trace", trace, trace_other); + self.fallback = merge_fallback(self.fallback, other.fallback); - let fallback = merge_fallback(fallback, fallback_other); + self.allow_header = merge_allow_header(self.allow_header, other.allow_header); - let allow_header = merge_allow_header(allow_header, allow_header_other); - - Self { - get, - head, - delete, - options, - patch, - post, - put, - trace, - fallback, - allow_header, - _request_body: PhantomData, - } + self } /// Apply a [`HandleErrorLayer`]. From 4fed037fead209fd643f710a82094916ac33fc08 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Mon, 25 Jul 2022 16:41:41 +0200 Subject: [PATCH 07/12] `MethodRouter::on_service_boxed_response_body` --- axum/src/routing/method_routing.rs | 76 +++++++++++++----------------- 1 file changed, 32 insertions(+), 44 deletions(-) diff --git a/axum/src/routing/method_routing.rs b/axum/src/routing/method_routing.rs index 336b3575c3..56528cd5eb 100644 --- a/axum/src/routing/method_routing.rs +++ b/axum/src/routing/method_routing.rs @@ -853,7 +853,7 @@ impl MethodRouter { self.layer(HandleErrorLayer::new(f)) } - fn on_service_boxed_response_body(self, filter: MethodFilter, svc: S) -> Self + fn on_service_boxed_response_body(mut self, filter: MethodFilter, svc: S) -> Self where S: Service, Error = E> + Clone + Send + 'static, S::Response: IntoResponse + 'static, @@ -882,116 +882,104 @@ impl MethodRouter { } } - // written with a pattern match like this to ensure we update all fields - let Self { - mut get, - mut head, - mut delete, - mut options, - mut patch, - mut post, - mut put, - mut trace, - fallback, - mut allow_header, - _request_body: _, - } = self; + // // written with a pattern match like this to ensure we update all fields + // let Self { + // mut get, + // mut head, + // mut delete, + // mut options, + // mut patch, + // mut post, + // mut put, + // mut trace, + // fallback, + // mut allow_header, + // _request_body: _, + // } = self; let svc = Route::new(svc); set_service( "GET", - &mut get, + &mut self.get, &svc, filter, MethodFilter::GET, - &mut allow_header, + &mut self.allow_header, &["GET", "HEAD"], ); set_service( "HEAD", - &mut head, + &mut self.head, &svc, filter, MethodFilter::HEAD, - &mut allow_header, + &mut self.allow_header, &["HEAD"], ); set_service( "TRACE", - &mut trace, + &mut self.trace, &svc, filter, MethodFilter::TRACE, - &mut allow_header, + &mut self.allow_header, &["TRACE"], ); set_service( "PUT", - &mut put, + &mut self.put, &svc, filter, MethodFilter::PUT, - &mut allow_header, + &mut self.allow_header, &["PUT"], ); set_service( "POST", - &mut post, + &mut self.post, &svc, filter, MethodFilter::POST, - &mut allow_header, + &mut self.allow_header, &["POST"], ); set_service( "PATCH", - &mut patch, + &mut self.patch, &svc, filter, MethodFilter::PATCH, - &mut allow_header, + &mut self.allow_header, &["PATCH"], ); set_service( "OPTIONS", - &mut options, + &mut self.options, &svc, filter, MethodFilter::OPTIONS, - &mut allow_header, + &mut self.allow_header, &["OPTIONS"], ); set_service( "DELETE", - &mut delete, + &mut self.delete, &svc, filter, MethodFilter::DELETE, - &mut allow_header, + &mut self.allow_header, &["DELETE"], ); - Self { - get, - head, - delete, - options, - patch, - post, - put, - trace, - fallback, - allow_header, - _request_body: PhantomData, - } + self } fn skip_allow_header(mut self) -> Self { From 985726b2bef807fd0db342a2d6b8532c8e101589 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Mon, 25 Jul 2022 16:47:31 +0200 Subject: [PATCH 08/12] `Router::call_route` --- axum/src/routing/method_routing.rs | 15 --------- axum/src/routing/mod.rs | 50 ++++++++++++++++++------------ 2 files changed, 30 insertions(+), 35 deletions(-) diff --git a/axum/src/routing/method_routing.rs b/axum/src/routing/method_routing.rs index 56528cd5eb..0817e6cd9d 100644 --- a/axum/src/routing/method_routing.rs +++ b/axum/src/routing/method_routing.rs @@ -882,21 +882,6 @@ impl MethodRouter { } } - // // written with a pattern match like this to ensure we update all fields - // let Self { - // mut get, - // mut head, - // mut delete, - // mut options, - // mut patch, - // mut post, - // mut put, - // mut trace, - // fallback, - // mut allow_header, - // _request_body: _, - // } = self; - let svc = Route::new(svc); set_service( diff --git a/axum/src/routing/mod.rs b/axum/src/routing/mod.rs index 40e1a79429..eda58c732c 100644 --- a/axum/src/routing/mod.rs +++ b/axum/src/routing/mod.rs @@ -427,28 +427,38 @@ where let id = *match_.value; #[cfg(feature = "matched-path")] - if let Some(matched_path) = self.node.route_id_to_path.get(&id) { - use crate::extract::MatchedPath; - - let matched_path = if let Some(previous) = req.extensions_mut().get::() { - // a previous `MatchedPath` might exist if we're inside a nested Router - let previous = if let Some(previous) = - previous.as_str().strip_suffix(NEST_TAIL_PARAM_CAPTURE) - { - previous + { + fn set_matched_path( + id: RouteId, + route_id_to_path: &HashMap>, + extensions: &mut http::Extensions, + ) { + if let Some(matched_path) = route_id_to_path.get(&id) { + use crate::extract::MatchedPath; + + let matched_path = if let Some(previous) = extensions.get::() { + // a previous `MatchedPath` might exist if we're inside a nested Router + let previous = if let Some(previous) = + previous.as_str().strip_suffix(NEST_TAIL_PARAM_CAPTURE) + { + previous + } else { + previous.as_str() + }; + + let matched_path = format!("{}{}", previous, matched_path); + matched_path.into() + } else { + Arc::clone(matched_path) + }; + extensions.insert(MatchedPath(matched_path)); } else { - previous.as_str() - }; + #[cfg(debug_assertions)] + panic!("should always have a matched path for a route id"); + } + } - let matched_path = format!("{}{}", previous, matched_path); - matched_path.into() - } else { - Arc::clone(matched_path) - }; - req.extensions_mut().insert(MatchedPath(matched_path)); - } else { - #[cfg(debug_assertions)] - panic!("should always have a matched path for a route id"); + set_matched_path(id, &self.node.route_id_to_path, req.extensions_mut()); } url_params::insert_url_params(req.extensions_mut(), match_.params); From 2f9cd06f7f89910c1399ce48d221b81df6be7596 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Mon, 25 Jul 2022 17:26:40 +0200 Subject: [PATCH 09/12] `MethodRouter::{layer, route_layer}` --- axum/src/routing/method_routing.rs | 55 ++++++++++++------------------ 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/axum/src/routing/method_routing.rs b/axum/src/routing/method_routing.rs index 0817e6cd9d..ecf38a0d4b 100644 --- a/axum/src/routing/method_routing.rs +++ b/axum/src/routing/method_routing.rs @@ -13,10 +13,9 @@ use bytes::BytesMut; use std::{ convert::Infallible, fmt, - marker::PhantomData, task::{Context, Poll}, }; -use tower::{service_fn, util::MapResponseLayer, ServiceBuilder}; +use tower::{service_fn, util::MapResponseLayer}; use tower_layer::Layer; use tower_service::Service; @@ -482,7 +481,6 @@ pub struct MethodRouter { trace: Option>, fallback: Fallback, allow_header: AllowHeader, - _request_body: PhantomData (B, E)>, } #[derive(Clone)] @@ -532,7 +530,6 @@ impl MethodRouter { trace: None, allow_header: AllowHeader::None, fallback: Fallback::Default(fallback), - _request_body: PhantomData, } } } @@ -723,12 +720,11 @@ impl MethodRouter { >>::Response: IntoResponse + 'static, >>::Future: Send + 'static, { - let layer = ServiceBuilder::new() - .layer_fn(Route::new) - .layer(MapResponseLayer::new(IntoResponse::into_response)) - .layer(layer) - .into_inner(); - let layer_fn = |s| layer.layer(s); + let layer_fn = |svc| { + let svc = layer.layer(svc); + let svc = MapResponseLayer::new(IntoResponse::into_response).layer(svc); + Route::new(svc) + }; MethodRouter { get: self.get.map(layer_fn), @@ -741,38 +737,33 @@ impl MethodRouter { trace: self.trace.map(layer_fn), fallback: self.fallback.map(layer_fn), allow_header: self.allow_header, - _request_body: PhantomData, } } #[doc = include_str!("../docs/method_routing/route_layer.md")] - pub fn route_layer(self, layer: L) -> MethodRouter + pub fn route_layer(mut self, layer: L) -> MethodRouter where L: Layer>, L::Service: Service, Error = E> + Clone + Send + 'static, >>::Response: IntoResponse + 'static, >>::Future: Send + 'static, { - let layer = ServiceBuilder::new() - .layer_fn(Route::new) - .layer(MapResponseLayer::new(IntoResponse::into_response)) - .layer(layer) - .into_inner(); - let layer_fn = |s| layer.layer(s); + let layer_fn = |svc| { + let svc = layer.layer(svc); + let svc = MapResponseLayer::new(IntoResponse::into_response).layer(svc); + Route::new(svc) + }; - MethodRouter { - get: self.get.map(layer_fn), - head: self.head.map(layer_fn), - delete: self.delete.map(layer_fn), - options: self.options.map(layer_fn), - patch: self.patch.map(layer_fn), - post: self.post.map(layer_fn), - put: self.put.map(layer_fn), - trace: self.trace.map(layer_fn), - fallback: self.fallback, - allow_header: self.allow_header, - _request_body: PhantomData, - } + self.get = self.get.map(layer_fn); + self.head = self.head.map(layer_fn); + self.delete = self.delete.map(layer_fn); + self.options = self.options.map(layer_fn); + self.patch = self.patch.map(layer_fn); + self.post = self.post.map(layer_fn); + self.put = self.put.map(layer_fn); + self.trace = self.trace.map(layer_fn); + + self } #[doc = include_str!("../docs/method_routing/merge.md")] @@ -1006,7 +997,6 @@ impl Clone for MethodRouter { trace: self.trace.clone(), fallback: self.fallback.clone(), allow_header: self.allow_header.clone(), - _request_body: PhantomData, } } } @@ -1064,7 +1054,6 @@ where trace, fallback, allow_header, - _request_body: _, } = self; call!(req, method, HEAD, head); From bbdba7d2a8eba7296ae8f134d5d0ca994e71ac1a Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Mon, 25 Jul 2022 17:36:31 +0200 Subject: [PATCH 10/12] revert example --- examples/hello-world/Cargo.toml | 1 - examples/hello-world/src/main.rs | 16 +++++----------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/examples/hello-world/Cargo.toml b/examples/hello-world/Cargo.toml index 8aa0615b51..6fbee18a76 100644 --- a/examples/hello-world/Cargo.toml +++ b/examples/hello-world/Cargo.toml @@ -7,4 +7,3 @@ publish = false [dependencies] axum = { path = "../../axum" } tokio = { version = "1.0", features = ["full"] } -tower = "0.4" diff --git a/examples/hello-world/src/main.rs b/examples/hello-world/src/main.rs index d2b357a401..ed115f6b2f 100644 --- a/examples/hello-world/src/main.rs +++ b/examples/hello-world/src/main.rs @@ -4,23 +4,17 @@ //! cd examples && cargo run -p example-hello-world //! ``` -use axum::{handler::Handler, response::Html, routing::get, Router}; +use axum::{response::Html, routing::get, Router}; use std::net::SocketAddr; -use tower::layer::util::Identity; #[tokio::main] async fn main() { - let app = Router::new() - .route( - "/", - get(handler.layer(Identity::new())) - .layer(Identity::new()) - .route_layer(Identity::new()), - ) - .layer(Identity::new()) - .route_layer(Identity::new()); + // build our application with a route + let app = Router::new().route("/", get(handler)); + // run it let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); + println!("listening on {}", addr); axum::Server::bind(&addr) .serve(app.into_make_service()) .await From f4c3f57e1da1dd5c342d74de0f07eb9473d8b849 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Mon, 25 Jul 2022 17:40:31 +0200 Subject: [PATCH 11/12] fix test --- axum/src/routing/method_routing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/axum/src/routing/method_routing.rs b/axum/src/routing/method_routing.rs index ecf38a0d4b..a32f936a55 100644 --- a/axum/src/routing/method_routing.rs +++ b/axum/src/routing/method_routing.rs @@ -1088,7 +1088,7 @@ mod tests { use axum_core::response::IntoResponse; use http::{header::ALLOW, HeaderMap}; use std::time::Duration; - use tower::{timeout::TimeoutLayer, Service, ServiceExt}; + use tower::{timeout::TimeoutLayer, Service, ServiceBuilder, ServiceExt}; use tower_http::{auth::RequireAuthorizationLayer, services::fs::ServeDir}; #[tokio::test] From 1bd680f20fc242a1c1d7a0190e5683c3b8e6f286 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Mon, 25 Jul 2022 19:56:29 +0200 Subject: [PATCH 12/12] move function to method on `AllowHeader` --- axum/src/routing/method_routing.rs | 35 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/axum/src/routing/method_routing.rs b/axum/src/routing/method_routing.rs index a32f936a55..f948fab74a 100644 --- a/axum/src/routing/method_routing.rs +++ b/axum/src/routing/method_routing.rs @@ -493,6 +493,22 @@ enum AllowHeader { Bytes(BytesMut), } +impl AllowHeader { + fn merge(self, other: Self) -> Self { + match (self, other) { + (AllowHeader::Skip, _) | (_, AllowHeader::Skip) => AllowHeader::Skip, + (AllowHeader::None, AllowHeader::None) => AllowHeader::None, + (AllowHeader::None, AllowHeader::Bytes(pick)) => AllowHeader::Bytes(pick), + (AllowHeader::Bytes(pick), AllowHeader::None) => AllowHeader::Bytes(pick), + (AllowHeader::Bytes(mut a), AllowHeader::Bytes(b)) => { + a.extend_from_slice(b","); + a.extend_from_slice(&b); + AllowHeader::Bytes(a) + } + } + } +} + impl fmt::Debug for MethodRouter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("MethodRouter") @@ -780,23 +796,6 @@ impl MethodRouter { } } - fn merge_allow_header( - allow_header: AllowHeader, - allow_header_other: AllowHeader, - ) -> AllowHeader { - match (allow_header, allow_header_other) { - (AllowHeader::Skip, _) | (_, AllowHeader::Skip) => AllowHeader::Skip, - (AllowHeader::None, AllowHeader::None) => AllowHeader::None, - (AllowHeader::None, AllowHeader::Bytes(pick)) => AllowHeader::Bytes(pick), - (AllowHeader::Bytes(pick), AllowHeader::None) => AllowHeader::Bytes(pick), - (AllowHeader::Bytes(mut a), AllowHeader::Bytes(b)) => { - a.extend_from_slice(b","); - a.extend_from_slice(&b); - AllowHeader::Bytes(a) - } - } - } - fn merge_fallback( fallback: Fallback, fallback_other: Fallback, @@ -822,7 +821,7 @@ impl MethodRouter { self.fallback = merge_fallback(self.fallback, other.fallback); - self.allow_header = merge_allow_header(self.allow_header, other.allow_header); + self.allow_header = self.allow_header.merge(other.allow_header); self }