tower_http/
lib.rs

1//! `async fn(HttpRequest) -> Result<HttpResponse, Error>`
2//!
3//! # Overview
4//!
5//! tower-http is a library that provides HTTP-specific middleware and utilities built on top of
6//! [tower].
7//!
8//! All middleware uses the [http] and [http-body] crates as the HTTP abstractions. That means
9//! they're compatible with any library or framework that also uses those crates, such as
10//! [hyper], [tonic], and [warp].
11//!
12//! # Example server
13//!
14//! This example shows how to apply middleware from tower-http to a [`Service`] and then run
15//! that service using [hyper].
16//!
17//! ```rust,no_run
18//! use tower_http::{
19//!     add_extension::AddExtensionLayer,
20//!     compression::CompressionLayer,
21//!     propagate_header::PropagateHeaderLayer,
22//!     sensitive_headers::SetSensitiveRequestHeadersLayer,
23//!     set_header::SetResponseHeaderLayer,
24//!     trace::TraceLayer,
25//!     validate_request::ValidateRequestHeaderLayer,
26//! };
27//! use tower::{ServiceBuilder, service_fn, BoxError};
28//! use http::{Request, Response, header::{HeaderName, CONTENT_TYPE, AUTHORIZATION}};
29//! use std::{sync::Arc, net::SocketAddr, convert::Infallible, iter::once};
30//! use bytes::Bytes;
31//! use http_body_util::Full;
32//! # struct DatabaseConnectionPool;
33//! # impl DatabaseConnectionPool {
34//! #     fn new() -> DatabaseConnectionPool { DatabaseConnectionPool }
35//! # }
36//! # fn content_length_from_response<B>(_: &http::Response<B>) -> Option<http::HeaderValue> { None }
37//! # async fn update_in_flight_requests_metric(count: usize) {}
38//!
39//! // Our request handler. This is where we would implement the application logic
40//! // for responding to HTTP requests...
41//! async fn handler(request: Request<Full<Bytes>>) -> Result<Response<Full<Bytes>>, BoxError> {
42//!     // ...
43//!     # todo!()
44//! }
45//!
46//! // Shared state across all request handlers --- in this case, a pool of database connections.
47//! struct State {
48//!     pool: DatabaseConnectionPool,
49//! }
50//!
51//! #[tokio::main]
52//! async fn main() {
53//!     // Construct the shared state.
54//!     let state = State {
55//!         pool: DatabaseConnectionPool::new(),
56//!     };
57//!
58//!     // Use tower's `ServiceBuilder` API to build a stack of tower middleware
59//!     // wrapping our request handler.
60//!     let service = ServiceBuilder::new()
61//!         // Mark the `Authorization` request header as sensitive so it doesn't show in logs
62//!         .layer(SetSensitiveRequestHeadersLayer::new(once(AUTHORIZATION)))
63//!         // High level logging of requests and responses
64//!         .layer(TraceLayer::new_for_http())
65//!         // Share an `Arc<State>` with all requests
66//!         .layer(AddExtensionLayer::new(Arc::new(state)))
67//!         // Compress responses
68//!         .layer(CompressionLayer::new())
69//!         // Propagate `X-Request-Id`s from requests to responses
70//!         .layer(PropagateHeaderLayer::new(HeaderName::from_static("x-request-id")))
71//!         // If the response has a known size set the `Content-Length` header
72//!         .layer(SetResponseHeaderLayer::overriding(CONTENT_TYPE, content_length_from_response))
73//!         // Authorize requests using a token
74//!         .layer(ValidateRequestHeaderLayer::bearer("passwordlol"))
75//!         // Accept only application/json, application/* and */* in a request's ACCEPT header
76//!         .layer(ValidateRequestHeaderLayer::accept("application/json"))
77//!         // Wrap a `Service` in our middleware stack
78//!         .service_fn(handler);
79//!     # let mut service = service;
80//!     # tower::Service::call(&mut service, Request::new(Full::default()));
81//! }
82//! ```
83//!
84//! Keep in mind that while this example uses [hyper], tower-http supports any HTTP
85//! client/server implementation that uses the [http] and [http-body] crates.
86//!
87//! # Example client
88//!
89//! tower-http middleware can also be applied to HTTP clients:
90//!
91//! ```rust,no_run
92//! use tower_http::{
93//!     decompression::DecompressionLayer,
94//!     set_header::SetRequestHeaderLayer,
95//!     trace::TraceLayer,
96//!     classify::StatusInRangeAsFailures,
97//! };
98//! use tower::{ServiceBuilder, Service, ServiceExt};
99//! use hyper_util::{rt::TokioExecutor, client::legacy::Client};
100//! use http_body_util::Full;
101//! use bytes::Bytes;
102//! use http::{Request, HeaderValue, header::USER_AGENT};
103//!
104//! #[tokio::main]
105//! async fn main() {
106//! let client = Client::builder(TokioExecutor::new()).build_http();
107//!     let mut client = ServiceBuilder::new()
108//!         // Add tracing and consider server errors and client
109//!         // errors as failures.
110//!         .layer(TraceLayer::new(
111//!             StatusInRangeAsFailures::new(400..=599).into_make_classifier()
112//!         ))
113//!         // Set a `User-Agent` header on all requests.
114//!         .layer(SetRequestHeaderLayer::overriding(
115//!             USER_AGENT,
116//!             HeaderValue::from_static("tower-http demo")
117//!         ))
118//!         // Decompress response bodies
119//!         .layer(DecompressionLayer::new())
120//!         // Wrap a `Client` in our middleware stack.
121//!         // This is possible because `Client` implements
122//!         // `tower::Service`.
123//!         .service(client);
124//!
125//!     // Make a request
126//!     let request = Request::builder()
127//!         .uri("http://example.com")
128//!         .body(Full::<Bytes>::default())
129//!         .unwrap();
130//!
131//!     let response = client
132//!         .ready()
133//!         .await
134//!         .unwrap()
135//!         .call(request)
136//!         .await
137//!         .unwrap();
138//! }
139//! ```
140//!
141//! # Feature Flags
142//!
143//! All middleware are disabled by default and can be enabled using [cargo features].
144//!
145//! For example, to enable the [`Trace`] middleware, add the "trace" feature flag in
146//! your `Cargo.toml`:
147//!
148//! ```toml
149//! tower-http = { version = "0.1", features = ["trace"] }
150//! ```
151//!
152//! You can use `"full"` to enable everything:
153//!
154//! ```toml
155//! tower-http = { version = "0.1", features = ["full"] }
156//! ```
157//!
158//! # Getting Help
159//!
160//! If you're new to tower its [guides] might help. In the tower-http repo we also have a [number
161//! of examples][examples] showing how to put everything together. You're also welcome to ask in
162//! the [`#tower` Discord channel][chat] or open an [issue] with your question.
163//!
164//! [tower]: https://crates.io/crates/tower
165//! [http]: https://crates.io/crates/http
166//! [http-body]: https://crates.io/crates/http-body
167//! [hyper]: https://crates.io/crates/hyper
168//! [guides]: https://github.com/tower-rs/tower/tree/master/guides
169//! [tonic]: https://crates.io/crates/tonic
170//! [warp]: https://crates.io/crates/warp
171//! [cargo features]: https://doc.rust-lang.org/cargo/reference/features.html
172//! [`AddExtension`]: crate::add_extension::AddExtension
173//! [`Service`]: https://docs.rs/tower/latest/tower/trait.Service.html
174//! [chat]: https://discord.gg/tokio
175//! [issue]: https://github.com/tower-rs/tower-http/issues/new
176//! [`Trace`]: crate::trace::Trace
177//! [examples]: https://github.com/tower-rs/tower-http/tree/master/examples
178
179#![warn(
180    clippy::all,
181    clippy::dbg_macro,
182    clippy::todo,
183    clippy::empty_enum,
184    clippy::enum_glob_use,
185    clippy::mem_forget,
186    clippy::unused_self,
187    clippy::filter_map_next,
188    clippy::needless_continue,
189    clippy::needless_borrow,
190    clippy::match_wildcard_for_single_variants,
191    clippy::if_let_mutex,
192    clippy::mismatched_target_os,
193    clippy::await_holding_lock,
194    clippy::match_on_vec_items,
195    clippy::imprecise_flops,
196    clippy::suboptimal_flops,
197    clippy::lossy_float_literal,
198    clippy::rest_pat_in_fully_bound_structs,
199    clippy::fn_params_excessive_bools,
200    clippy::exit,
201    clippy::inefficient_to_string,
202    clippy::linkedlist,
203    clippy::macro_use_imports,
204    clippy::option_option,
205    clippy::verbose_file_reads,
206    clippy::unnested_or_patterns,
207    rust_2018_idioms,
208    future_incompatible,
209    nonstandard_style,
210    missing_docs
211)]
212#![deny(unreachable_pub)]
213#![allow(
214    elided_lifetimes_in_paths,
215    // TODO: Remove this once the MSRV bumps to 1.42.0 or above.
216    clippy::match_like_matches_macro,
217    clippy::type_complexity
218)]
219#![forbid(unsafe_code)]
220#![cfg_attr(docsrs, feature(doc_auto_cfg))]
221#![cfg_attr(test, allow(clippy::float_cmp))]
222
223#[macro_use]
224pub(crate) mod macros;
225
226#[cfg(test)]
227mod test_helpers;
228
229#[cfg(feature = "auth")]
230pub mod auth;
231
232#[cfg(feature = "set-header")]
233pub mod set_header;
234
235#[cfg(feature = "propagate-header")]
236pub mod propagate_header;
237
238#[cfg(any(
239    feature = "compression-br",
240    feature = "compression-deflate",
241    feature = "compression-gzip",
242    feature = "compression-zstd",
243))]
244pub mod compression;
245
246#[cfg(feature = "add-extension")]
247pub mod add_extension;
248
249#[cfg(feature = "sensitive-headers")]
250pub mod sensitive_headers;
251
252#[cfg(any(
253    feature = "decompression-br",
254    feature = "decompression-deflate",
255    feature = "decompression-gzip",
256    feature = "decompression-zstd",
257))]
258pub mod decompression;
259
260#[cfg(any(
261    feature = "compression-br",
262    feature = "compression-deflate",
263    feature = "compression-gzip",
264    feature = "compression-zstd",
265    feature = "decompression-br",
266    feature = "decompression-deflate",
267    feature = "decompression-gzip",
268    feature = "decompression-zstd",
269    feature = "fs" // Used for serving precompressed static files as well
270))]
271mod content_encoding;
272
273#[cfg(any(
274    feature = "compression-br",
275    feature = "compression-deflate",
276    feature = "compression-gzip",
277    feature = "compression-zstd",
278    feature = "decompression-br",
279    feature = "decompression-deflate",
280    feature = "decompression-gzip",
281    feature = "decompression-zstd",
282))]
283mod compression_utils;
284
285#[cfg(any(
286    feature = "compression-br",
287    feature = "compression-deflate",
288    feature = "compression-gzip",
289    feature = "compression-zstd",
290    feature = "decompression-br",
291    feature = "decompression-deflate",
292    feature = "decompression-gzip",
293    feature = "decompression-zstd",
294))]
295pub use compression_utils::CompressionLevel;
296
297#[cfg(feature = "map-response-body")]
298pub mod map_response_body;
299
300#[cfg(feature = "map-request-body")]
301pub mod map_request_body;
302
303#[cfg(feature = "trace")]
304pub mod trace;
305
306#[cfg(feature = "follow-redirect")]
307pub mod follow_redirect;
308
309#[cfg(feature = "limit")]
310pub mod limit;
311
312#[cfg(feature = "metrics")]
313pub mod metrics;
314
315#[cfg(feature = "cors")]
316pub mod cors;
317
318#[cfg(feature = "request-id")]
319pub mod request_id;
320
321#[cfg(feature = "catch-panic")]
322pub mod catch_panic;
323
324#[cfg(feature = "set-status")]
325pub mod set_status;
326
327#[cfg(feature = "timeout")]
328pub mod timeout;
329
330#[cfg(feature = "normalize-path")]
331pub mod normalize_path;
332
333pub mod classify;
334pub mod services;
335
336#[cfg(feature = "util")]
337mod builder;
338
339#[cfg(feature = "util")]
340#[doc(inline)]
341pub use self::builder::ServiceBuilderExt;
342
343#[cfg(feature = "validate-request")]
344pub mod validate_request;
345
346#[cfg(any(
347    feature = "catch-panic",
348    feature = "decompression-br",
349    feature = "decompression-deflate",
350    feature = "decompression-gzip",
351    feature = "decompression-zstd",
352    feature = "fs",
353    feature = "limit",
354))]
355pub mod body;
356
357/// The latency unit used to report latencies by middleware.
358#[non_exhaustive]
359#[derive(Copy, Clone, Debug)]
360pub enum LatencyUnit {
361    /// Use seconds.
362    Seconds,
363    /// Use milliseconds.
364    Millis,
365    /// Use microseconds.
366    Micros,
367    /// Use nanoseconds.
368    Nanos,
369}
370
371/// Alias for a type-erased error type.
372pub type BoxError = Box<dyn std::error::Error + Send + Sync>;
373
374mod sealed {
375    #[allow(unreachable_pub, unused)]
376    pub trait Sealed<T> {}
377}