use tower::ServiceBuilder; #[allow(unused_imports)] use http::header::HeaderName; #[allow(unused_imports)] use tower_layer::Stack; mod sealed { #[allow(unreachable_pub, unused)] pub trait Sealed {} } /// Extension trait that adds methods to [`tower::ServiceBuilder`] for adding middleware from /// tower-http. /// /// [`Service`]: tower::Service /// /// # Example /// /// ```rust /// use http::{Request, Response, header::HeaderName}; /// use bytes::Bytes; /// use http_body_util::Full; /// use std::{time::Duration, convert::Infallible}; /// use tower::{ServiceBuilder, ServiceExt, Service}; /// use tower_http::ServiceBuilderExt; /// /// async fn handle(request: Request>) -> Result>, Infallible> { /// Ok(Response::new(Full::default())) /// } /// /// # #[tokio::main] /// # async fn main() { /// let service = ServiceBuilder::new() /// // Methods from tower /// .timeout(Duration::from_secs(30)) /// // Methods from tower-http /// .trace_for_http() /// .propagate_header(HeaderName::from_static("x-request-id")) /// .service_fn(handle); /// # let mut service = service; /// # service.ready().await.unwrap().call(Request::new(Full::default())).await.unwrap(); /// # } /// ``` #[cfg(feature = "util")] // ^ work around rustdoc not inferring doc(cfg)s for cfg's from surrounding scopes pub trait ServiceBuilderExt: sealed::Sealed + Sized { /// Propagate a header from the request to the response. /// /// See [`tower_http::propagate_header`] for more details. /// /// [`tower_http::propagate_header`]: crate::propagate_header #[cfg(feature = "propagate-header")] fn propagate_header( self, header: HeaderName, ) -> ServiceBuilder>; /// Add some shareable value to [request extensions]. /// /// See [`tower_http::add_extension`] for more details. /// /// [`tower_http::add_extension`]: crate::add_extension /// [request extensions]: https://docs.rs/http/latest/http/struct.Extensions.html #[cfg(feature = "add-extension")] fn add_extension( self, value: T, ) -> ServiceBuilder, L>>; /// Apply a transformation to the request body. /// /// See [`tower_http::map_request_body`] for more details. /// /// [`tower_http::map_request_body`]: crate::map_request_body #[cfg(feature = "map-request-body")] fn map_request_body( self, f: F, ) -> ServiceBuilder, L>>; /// Apply a transformation to the response body. /// /// See [`tower_http::map_response_body`] for more details. /// /// [`tower_http::map_response_body`]: crate::map_response_body #[cfg(feature = "map-response-body")] fn map_response_body( self, f: F, ) -> ServiceBuilder, L>>; /// Compresses response bodies. /// /// See [`tower_http::compression`] for more details. /// /// [`tower_http::compression`]: crate::compression #[cfg(any( feature = "compression-br", feature = "compression-deflate", feature = "compression-gzip", feature = "compression-zstd", ))] fn compression(self) -> ServiceBuilder>; /// Decompress response bodies. /// /// See [`tower_http::decompression`] for more details. /// /// [`tower_http::decompression`]: crate::decompression #[cfg(any( feature = "decompression-br", feature = "decompression-deflate", feature = "decompression-gzip", feature = "decompression-zstd", ))] fn decompression(self) -> ServiceBuilder>; /// High level tracing that classifies responses using HTTP status codes. /// /// This method does not support customizing the output, to do that use [`TraceLayer`] /// instead. /// /// See [`tower_http::trace`] for more details. /// /// [`tower_http::trace`]: crate::trace /// [`TraceLayer`]: crate::trace::TraceLayer #[cfg(feature = "trace")] fn trace_for_http( self, ) -> ServiceBuilder, L>>; /// High level tracing that classifies responses using gRPC headers. /// /// This method does not support customizing the output, to do that use [`TraceLayer`] /// instead. /// /// See [`tower_http::trace`] for more details. /// /// [`tower_http::trace`]: crate::trace /// [`TraceLayer`]: crate::trace::TraceLayer #[cfg(feature = "trace")] fn trace_for_grpc( self, ) -> ServiceBuilder, L>>; /// Follow redirect resposes using the [`Standard`] policy. /// /// See [`tower_http::follow_redirect`] for more details. /// /// [`tower_http::follow_redirect`]: crate::follow_redirect /// [`Standard`]: crate::follow_redirect::policy::Standard #[cfg(feature = "follow-redirect")] fn follow_redirects( self, ) -> ServiceBuilder< Stack< crate::follow_redirect::FollowRedirectLayer, L, >, >; /// Mark headers as [sensitive] on both requests and responses. /// /// See [`tower_http::sensitive_headers`] for more details. /// /// [sensitive]: https://docs.rs/http/latest/http/header/struct.HeaderValue.html#method.set_sensitive /// [`tower_http::sensitive_headers`]: crate::sensitive_headers #[cfg(feature = "sensitive-headers")] fn sensitive_headers( self, headers: I, ) -> ServiceBuilder> where I: IntoIterator; /// Mark headers as [sensitive] on requests. /// /// See [`tower_http::sensitive_headers`] for more details. /// /// [sensitive]: https://docs.rs/http/latest/http/header/struct.HeaderValue.html#method.set_sensitive /// [`tower_http::sensitive_headers`]: crate::sensitive_headers #[cfg(feature = "sensitive-headers")] fn sensitive_request_headers( self, headers: std::sync::Arc<[HeaderName]>, ) -> ServiceBuilder>; /// Mark headers as [sensitive] on responses. /// /// See [`tower_http::sensitive_headers`] for more details. /// /// [sensitive]: https://docs.rs/http/latest/http/header/struct.HeaderValue.html#method.set_sensitive /// [`tower_http::sensitive_headers`]: crate::sensitive_headers #[cfg(feature = "sensitive-headers")] fn sensitive_response_headers( self, headers: std::sync::Arc<[HeaderName]>, ) -> ServiceBuilder>; /// Insert a header into the request. /// /// If a previous value exists for the same header, it is removed and replaced with the new /// header value. /// /// See [`tower_http::set_header`] for more details. /// /// [`tower_http::set_header`]: crate::set_header #[cfg(feature = "set-header")] fn override_request_header( self, header_name: HeaderName, make: M, ) -> ServiceBuilder, L>>; /// Append a header into the request. /// /// If previous values exist, the header will have multiple values. /// /// See [`tower_http::set_header`] for more details. /// /// [`tower_http::set_header`]: crate::set_header #[cfg(feature = "set-header")] fn append_request_header( self, header_name: HeaderName, make: M, ) -> ServiceBuilder, L>>; /// Insert a header into the request, if the header is not already present. /// /// See [`tower_http::set_header`] for more details. /// /// [`tower_http::set_header`]: crate::set_header #[cfg(feature = "set-header")] fn insert_request_header_if_not_present( self, header_name: HeaderName, make: M, ) -> ServiceBuilder, L>>; /// Insert a header into the response. /// /// If a previous value exists for the same header, it is removed and replaced with the new /// header value. /// /// See [`tower_http::set_header`] for more details. /// /// [`tower_http::set_header`]: crate::set_header #[cfg(feature = "set-header")] fn override_response_header( self, header_name: HeaderName, make: M, ) -> ServiceBuilder, L>>; /// Append a header into the response. /// /// If previous values exist, the header will have multiple values. /// /// See [`tower_http::set_header`] for more details. /// /// [`tower_http::set_header`]: crate::set_header #[cfg(feature = "set-header")] fn append_response_header( self, header_name: HeaderName, make: M, ) -> ServiceBuilder, L>>; /// Insert a header into the response, if the header is not already present. /// /// See [`tower_http::set_header`] for more details. /// /// [`tower_http::set_header`]: crate::set_header #[cfg(feature = "set-header")] fn insert_response_header_if_not_present( self, header_name: HeaderName, make: M, ) -> ServiceBuilder, L>>; /// Add request id header and extension. /// /// See [`tower_http::request_id`] for more details. /// /// [`tower_http::request_id`]: crate::request_id #[cfg(feature = "request-id")] fn set_request_id( self, header_name: HeaderName, make_request_id: M, ) -> ServiceBuilder, L>> where M: crate::request_id::MakeRequestId; /// Add request id header and extension, using `x-request-id` as the header name. /// /// See [`tower_http::request_id`] for more details. /// /// [`tower_http::request_id`]: crate::request_id #[cfg(feature = "request-id")] fn set_x_request_id( self, make_request_id: M, ) -> ServiceBuilder, L>> where M: crate::request_id::MakeRequestId, { self.set_request_id(crate::request_id::X_REQUEST_ID, make_request_id) } /// Propgate request ids from requests to responses. /// /// See [`tower_http::request_id`] for more details. /// /// [`tower_http::request_id`]: crate::request_id #[cfg(feature = "request-id")] fn propagate_request_id( self, header_name: HeaderName, ) -> ServiceBuilder>; /// Propgate request ids from requests to responses, using `x-request-id` as the header name. /// /// See [`tower_http::request_id`] for more details. /// /// [`tower_http::request_id`]: crate::request_id #[cfg(feature = "request-id")] fn propagate_x_request_id( self, ) -> ServiceBuilder> { self.propagate_request_id(crate::request_id::X_REQUEST_ID) } /// Catch panics and convert them into `500 Internal Server` responses. /// /// See [`tower_http::catch_panic`] for more details. /// /// [`tower_http::catch_panic`]: crate::catch_panic #[cfg(feature = "catch-panic")] fn catch_panic( self, ) -> ServiceBuilder< Stack, L>, >; /// Intercept requests with over-sized payloads and convert them into /// `413 Payload Too Large` responses. /// /// See [`tower_http::limit`] for more details. /// /// [`tower_http::limit`]: crate::limit #[cfg(feature = "limit")] fn request_body_limit( self, limit: usize, ) -> ServiceBuilder>; /// Remove trailing slashes from paths. /// /// See [`tower_http::normalize_path`] for more details. /// /// [`tower_http::normalize_path`]: crate::normalize_path #[cfg(feature = "normalize-path")] fn trim_trailing_slash( self, ) -> ServiceBuilder>; /// Append trailing slash to paths. /// /// See [`tower_http::normalize_path`] for more details. /// /// [`tower_http::normalize_path`]: crate::normalize_path #[cfg(feature = "normalize-path")] fn append_trailing_slash( self, ) -> ServiceBuilder>; } impl sealed::Sealed for ServiceBuilder {} impl ServiceBuilderExt for ServiceBuilder { #[cfg(feature = "propagate-header")] fn propagate_header( self, header: HeaderName, ) -> ServiceBuilder> { self.layer(crate::propagate_header::PropagateHeaderLayer::new(header)) } #[cfg(feature = "add-extension")] fn add_extension( self, value: T, ) -> ServiceBuilder, L>> { self.layer(crate::add_extension::AddExtensionLayer::new(value)) } #[cfg(feature = "map-request-body")] fn map_request_body( self, f: F, ) -> ServiceBuilder, L>> { self.layer(crate::map_request_body::MapRequestBodyLayer::new(f)) } #[cfg(feature = "map-response-body")] fn map_response_body( self, f: F, ) -> ServiceBuilder, L>> { self.layer(crate::map_response_body::MapResponseBodyLayer::new(f)) } #[cfg(any( feature = "compression-br", feature = "compression-deflate", feature = "compression-gzip", feature = "compression-zstd", ))] fn compression(self) -> ServiceBuilder> { self.layer(crate::compression::CompressionLayer::new()) } #[cfg(any( feature = "decompression-br", feature = "decompression-deflate", feature = "decompression-gzip", feature = "decompression-zstd", ))] fn decompression(self) -> ServiceBuilder> { self.layer(crate::decompression::DecompressionLayer::new()) } #[cfg(feature = "trace")] fn trace_for_http( self, ) -> ServiceBuilder, L>> { self.layer(crate::trace::TraceLayer::new_for_http()) } #[cfg(feature = "trace")] fn trace_for_grpc( self, ) -> ServiceBuilder, L>> { self.layer(crate::trace::TraceLayer::new_for_grpc()) } #[cfg(feature = "follow-redirect")] fn follow_redirects( self, ) -> ServiceBuilder< Stack< crate::follow_redirect::FollowRedirectLayer, L, >, > { self.layer(crate::follow_redirect::FollowRedirectLayer::new()) } #[cfg(feature = "sensitive-headers")] fn sensitive_headers( self, headers: I, ) -> ServiceBuilder> where I: IntoIterator, { self.layer(crate::sensitive_headers::SetSensitiveHeadersLayer::new( headers, )) } #[cfg(feature = "sensitive-headers")] fn sensitive_request_headers( self, headers: std::sync::Arc<[HeaderName]>, ) -> ServiceBuilder> { self.layer(crate::sensitive_headers::SetSensitiveRequestHeadersLayer::from_shared(headers)) } #[cfg(feature = "sensitive-headers")] fn sensitive_response_headers( self, headers: std::sync::Arc<[HeaderName]>, ) -> ServiceBuilder> { self.layer(crate::sensitive_headers::SetSensitiveResponseHeadersLayer::from_shared(headers)) } #[cfg(feature = "set-header")] fn override_request_header( self, header_name: HeaderName, make: M, ) -> ServiceBuilder, L>> { self.layer(crate::set_header::SetRequestHeaderLayer::overriding( header_name, make, )) } #[cfg(feature = "set-header")] fn append_request_header( self, header_name: HeaderName, make: M, ) -> ServiceBuilder, L>> { self.layer(crate::set_header::SetRequestHeaderLayer::appending( header_name, make, )) } #[cfg(feature = "set-header")] fn insert_request_header_if_not_present( self, header_name: HeaderName, make: M, ) -> ServiceBuilder, L>> { self.layer(crate::set_header::SetRequestHeaderLayer::if_not_present( header_name, make, )) } #[cfg(feature = "set-header")] fn override_response_header( self, header_name: HeaderName, make: M, ) -> ServiceBuilder, L>> { self.layer(crate::set_header::SetResponseHeaderLayer::overriding( header_name, make, )) } #[cfg(feature = "set-header")] fn append_response_header( self, header_name: HeaderName, make: M, ) -> ServiceBuilder, L>> { self.layer(crate::set_header::SetResponseHeaderLayer::appending( header_name, make, )) } #[cfg(feature = "set-header")] fn insert_response_header_if_not_present( self, header_name: HeaderName, make: M, ) -> ServiceBuilder, L>> { self.layer(crate::set_header::SetResponseHeaderLayer::if_not_present( header_name, make, )) } #[cfg(feature = "request-id")] fn set_request_id( self, header_name: HeaderName, make_request_id: M, ) -> ServiceBuilder, L>> where M: crate::request_id::MakeRequestId, { self.layer(crate::request_id::SetRequestIdLayer::new( header_name, make_request_id, )) } #[cfg(feature = "request-id")] fn propagate_request_id( self, header_name: HeaderName, ) -> ServiceBuilder> { self.layer(crate::request_id::PropagateRequestIdLayer::new(header_name)) } #[cfg(feature = "catch-panic")] fn catch_panic( self, ) -> ServiceBuilder< Stack, L>, > { self.layer(crate::catch_panic::CatchPanicLayer::new()) } #[cfg(feature = "limit")] fn request_body_limit( self, limit: usize, ) -> ServiceBuilder> { self.layer(crate::limit::RequestBodyLimitLayer::new(limit)) } #[cfg(feature = "normalize-path")] fn trim_trailing_slash( self, ) -> ServiceBuilder> { self.layer(crate::normalize_path::NormalizePathLayer::trim_trailing_slash()) } #[cfg(feature = "normalize-path")] fn append_trailing_slash( self, ) -> ServiceBuilder> { self.layer(crate::normalize_path::NormalizePathLayer::append_trailing_slash()) } }