From e0a463b463700e45d455abe2f7414c2cbf7fe7d1 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Mon, 3 Jan 2022 16:28:33 +0100 Subject: [PATCH] Optional extractor extensions (#685) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix inconsistent indentation in axum/Cargo.toml * Make MatchedPath and OriginalUri extractors and logic for them optional … they add some runtime cost to handling any request that goes through a Router, which only makes sense if they actually get used. Enable both features by default for convenience. --- axum/Cargo.toml | 16 +++++++++------- axum/src/extract/mod.rs | 16 +++++++++++++--- axum/src/extract/request_parts.rs | 2 ++ axum/src/lib.rs | 5 ++++- axum/src/routing/mod.rs | 23 +++++++++++++---------- 5 files changed, 41 insertions(+), 21 deletions(-) diff --git a/axum/Cargo.toml b/axum/Cargo.toml index 69b21b9d..ee75de9d 100644 --- a/axum/Cargo.toml +++ b/axum/Cargo.toml @@ -11,11 +11,13 @@ readme = "README.md" repository = "https://github.com/tokio-rs/axum" [features] -default = ["http1", "json", "tower-log"] +default = ["http1", "json", "matched-path", "original-uri", "tower-log"] http1 = ["hyper/http1"] http2 = ["hyper/http2"] json = ["serde_json"] +matched-path = [] multipart = ["multer"] +original-uri = [] tower-log = ["tower/log"] ws = ["tokio-tungstenite", "sha-1", "base64"] @@ -84,10 +86,10 @@ rustdoc-args = ["--cfg", "docsrs"] [package.metadata.playground] features = [ - "http1", - "http2", - "json", - "multipart", - "tower", - "ws", + "http1", + "http2", + "json", + "multipart", + "tower", + "ws", ] diff --git a/axum/src/extract/mod.rs b/axum/src/extract/mod.rs index 4fdd0ba0..68ba94e4 100644 --- a/axum/src/extract/mod.rs +++ b/axum/src/extract/mod.rs @@ -15,7 +15,6 @@ pub mod ws; mod content_length_limit; mod extension; mod form; -mod matched_path; mod query; mod raw_query; mod request_parts; @@ -31,17 +30,23 @@ pub use self::{ extension::Extension, extractor_middleware::extractor_middleware, form::Form, - matched_path::MatchedPath, path::Path, query::Query, raw_query::RawQuery, - request_parts::OriginalUri, request_parts::{BodyStream, RawBody}, }; #[doc(no_inline)] #[cfg(feature = "json")] pub use crate::Json; +#[cfg(feature = "matched-path")] +mod matched_path; + +#[cfg(feature = "matched-path")] +#[cfg_attr(docsrs, doc(cfg(feature = "matched-path")))] +#[doc(inline)] +pub use self::matched_path::MatchedPath; + #[cfg(feature = "multipart")] #[cfg_attr(docsrs, doc(cfg(feature = "multipart")))] pub mod multipart; @@ -51,6 +56,11 @@ pub mod multipart; #[doc(inline)] pub use self::multipart::Multipart; +#[cfg(feature = "original-uri")] +#[cfg_attr(docsrs, doc(cfg(feature = "original-uri")))] +#[doc(inline)] +pub use self::request_parts::OriginalUri; + #[cfg(feature = "ws")] #[cfg_attr(docsrs, doc(cfg(feature = "ws")))] #[doc(inline)] diff --git a/axum/src/extract/request_parts.rs b/axum/src/extract/request_parts.rs index 6764bdc3..7994caf8 100644 --- a/axum/src/extract/request_parts.rs +++ b/axum/src/extract/request_parts.rs @@ -80,9 +80,11 @@ use sync_wrapper::SyncWrapper; /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # }; /// ``` +#[cfg(feature = "original-uri")] #[derive(Debug, Clone)] pub struct OriginalUri(pub Uri); +#[cfg(feature = "original-uri")] #[async_trait] impl FromRequest for OriginalUri where diff --git a/axum/src/lib.rs b/axum/src/lib.rs index e7cdb9fc..29ea6a17 100644 --- a/axum/src/lib.rs +++ b/axum/src/lib.rs @@ -375,12 +375,16 @@ //! `http1` | Enables hyper's `http1` feature | Yes //! `http2` | Enables hyper's `http2` feature | No //! `json` | Enables the [`Json`] type and some similar convenience functionality | Yes +//! `matched-path` | Enables capturing of every request's router path and the [`MatchedPath`] extractor | Yes //! `multipart` | Enables parsing `multipart/form-data` requests with [`Multipart`] | No +//! `original-uri` | Enables capturing of every request's original URI and the [`OriginalUri`] extractor | Yes //! `tower-log` | Enables `tower`'s `log` feature | Yes //! `ws` | Enables WebSockets support via [`extract::ws`] | No //! //! [`TypedHeader`]: crate::extract::TypedHeader +//! [`MatchedPath`]: crate::extract::MatchedPath //! [`Multipart`]: crate::extract::Multipart +//! [`OriginalUri`]: crate::extract::OriginalUri //! [`tower`]: https://crates.io/crates/tower //! [`tower-http`]: https://crates.io/crates/tower-http //! [`tokio`]: http://crates.io/crates/tokio @@ -392,7 +396,6 @@ //! [examples]: https://github.com/tokio-rs/axum/tree/main/examples //! [`Router::merge`]: crate::routing::Router::merge //! [`axum::Server`]: hyper::server::Server -//! [`OriginalUri`]: crate::extract::OriginalUri //! [`Service`]: tower::Service //! [`Service::poll_ready`]: tower::Service::poll_ready //! [`Service`'s]: tower::Service diff --git a/axum/src/routing/mod.rs b/axum/src/routing/mod.rs index 08c0c37b..1d44101c 100644 --- a/axum/src/routing/mod.rs +++ b/axum/src/routing/mod.rs @@ -3,13 +3,8 @@ use self::{future::RouterFuture, not_found::NotFound}; use crate::{ body::{boxed, Body, Bytes, HttpBody}, - extract::{ - connect_info::{Connected, IntoMakeServiceWithConnectInfo}, - MatchedPath, OriginalUri, - }, - response::IntoResponse, - response::Redirect, - response::Response, + extract::connect_info::{Connected, IntoMakeServiceWithConnectInfo}, + response::{Response, Redirect, IntoResponse}, routing::strip_prefix::StripPrefix, util::{try_downcast, ByteStr, PercentDecodedByteStr}, BoxError, @@ -405,7 +400,10 @@ where let id = *match_.value; req.extensions_mut().insert(id); + #[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) = @@ -476,9 +474,14 @@ where #[inline] fn call(&mut self, mut req: Request) -> Self::Future { - if req.extensions().get::().is_none() { - let original_uri = OriginalUri(req.uri().clone()); - req.extensions_mut().insert(original_uri); + #[cfg(feature = "original-uri")] + { + use crate::extract::OriginalUri; + + if req.extensions().get::().is_none() { + let original_uri = OriginalUri(req.uri().clone()); + req.extensions_mut().insert(original_uri); + } } let path = req.uri().path().to_owned();