NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
crates.io · #272 most downloaded on crates.io
Tower middleware and utilities for HTTP clients and servers
Last release 1 months ago
31 Aug 2026
Release timing varies
gaps range from 2 weeks to 7 months
Most releases are documented
notes for 28 of 33 stable releases
6 versions withdrawn
withdrawn after publishing
10 years old
39 releases · first in 2017
fs : add ServeDir::redirect_to_trailing_slash() to serve directory indexes directly instead of first redirecting to the trailing-slash path. The redir
fs: add ServeDir::redirect_to_trailing_slash() to serve directory indexes directly instead of first redirecting to the trailing-slash path. The redirect remains the default (#728)fs: add ignore_multi_range_requests() to ServeDir and ServeFile, serving the full representation when a request asks for multiple byte ranges. The existing 416 Range Not Satisfiable response remains the default (#727)request-id: the constructors and accessors on the request-id layers, services, and RequestId are now const fn, so they can be used in const context (#716)fs: the minimum http-range-header requirement is now 0.4.2 (#661)fs: make ServeDir::try_call propagate expected filesystem404 Not Found responses (#718)decompression: don't end the body when a data frame with no remaining bytesdecompression: return a body error when a data frame with remaining bytesfs: multipart range requests are now rejected before range validation, so416 Range Not Satisfiable with aCannot serve multipart range requests body instead of a genericfs: range error responses no longer carry representation headers such asContent-Type and Content-Encoding (#727)set-header: SetMultipleResponseHeadersLayer and SetMultipleResponseHeaderClone regardless of the response body type, matching the fix appliedOne column per quarter.
csrf : add cross-site request forgery (CSRF) protection middleware, porting the cross-origin protection scheme introduced in Go 1.25
csrf: add cross-site request forgery (CSRF) protection middleware, porting the cross-origin protection scheme introduced in Go 1.25 (#699)
use tower::ServiceBuilder;
use tower_http::csrf::CsrfLayer;
// Rejects cross-origin state-changing requests using `Sec-Fetch-Site`,
// an `Origin` allow-list, and an `Origin`/`Host` fallback. No per-request
// token state required.
let layer = CsrfLayer::new().add_trusted_origin("https://example.com")?;
let service = ServiceBuilder::new().layer(layer).service_fn(handler);timeout: add DeadlineBody for non-resetting body timeouts, applied via the new RequestBodyDeadlineLayer and ResponseBodyDeadlineLayer (#688)
Unlike TimeoutBody, which resets its deadline on every frame, DeadlineBody caps the total time of a body transfer. A slow client trickling one byte at a time never trips an idle timeout but will trip a deadline.
use std::time::Duration;
use tower::ServiceBuilder;
use tower_http::timeout::RequestBodyDeadlineLayer;
// Abort the request body transfer after 30s total, regardless of how
// frequently data arrives.
let service = ServiceBuilder::new()
.layer(RequestBodyDeadlineLayer::new(Duration::from_secs(30)))
.service_fn(handler);fs: add strong ETag support to ServeDir, including If-Match and If-None-Match precondition handling per RFC 9110. 304 Not Modified responses now carry the ETag and Last-Modified validators (#691)
fs: add a Backend trait to make ServeDir work with non-filesystem sources (e.g. embedded assets or object storage). The default TokioBackend preserves existing behavior. Use ServeDir::with_backend() to plug in custom implementations (#684)
use tower_http::services::fs::ServeDir;
// `MyBackend` implements `tower_http::services::fs::Backend`.
// The default `ServeDir::new()` continues to use `TokioBackend` (local FS).
let service = ServeDir::with_backend("assets", MyBackend::new());fs: add html_as_default_extension option to ServeDir, appending .html when the request path has no extension (#519)
fs: add redirect_path_prefix option to ServeDir, prepending a prefix on trailing-slash redirects so the service can be mounted under a sub-path (#486)
validate-request: add ValidateRequestHeaderLayer::has_header_value() to reject requests when a header does not have an expected value (#360)
body: UnsyncBoxBody::new() constructor and From<ServeFileSystemResponseBody> conversion to avoid double-boxing when combining ServeDir responses with other body types (#537)
limit: implement Default for limit::ResponseBody when the wrapped body also implements Default (#679)
breaking: compression: the middleware now handles the * wildcard and identity;q=0 in Accept-Encoding per RFC 9110 §12.5.3. Requests that previously fell back to identity (e.g. *;q=0 or identity;q=0 with no other acceptable encoding) now receive a 406 Not Acceptable response. Clients that explicitly reject all encodings without listing an alternative will see different behavior. (#693)
breaking: compression: upgrade the SizeAbove predicate threshold from u16 to u64, allowing minimum sizes above 64 KiB (#704)
breaking: remove the implicit no-op tokio and async-compression features. These were kept as no-op features in 0.6.x for backwards compatibility after the switch to dep: syntax in #642. Downstream crates that activate tower-http/tokio or tower http/async-compression should remove those feature entries; the underlying dependencies are still pulled in transitively by the features that need them (e.g. compression-gzip, fs, timeout). (#628)
breaking: trace/classify: include the gRPC error message in tracing output. GrpcCode and GrpcFailureClass are now #[non_exhaustive], and GrpcStatus is exported from the classify module (#422)
breaking: follow-redirect: FollowRedirect now forwards request Extensions to redirected requests instead of dropping them. The Standard policy drops extensions on cross-origin redirections (same-origin keeps them). Opt out with FollowRedirectLayer::preserve_extensions(false); keep specific types with FilterCredentials::allow_extension::<T>() or all of them with keep_all_extensions(). (#706)
use tower_http::follow_redirect::FollowRedirectLayer;
// 0.7.0 forwards request `Extensions` across redirects by default.
// Restore the previous behavior (drop all extensions) with:
let layer = FollowRedirectLayer::new().preserve_extensions(false);breaking: follow-redirect: header and extension filtering is now cumulative. A value a policy drops on one hop is no longer replayed on later hops, so FilterCredentials no longer re-sends Cookie/Authorization to a same-origin target reached after cross-origin hop. Custom Policy::on_request impls now see the previous hop's filtered request, not the original. (#706)
trace: DefaultOnRequest, DefaultOnResponse, DefaultOnFailure, and DefaultOnEos now explicitly parent their tracing events to the request span rather than relying on the ambient span context. This fixes intermittent cases where events could appear without their request span attached (#690)
cors: relax the Vary header defaults (#674)
MSRV bumped from 1.64 to 1.65 (#684)
fs: ServeDir and ServeFile now emit a Vary: Accept-Encoding responseservices: reject a trailing slash for file paths. File requests with a trailing slash now return 404 Not Found instead of serving the file (#678)fs: fix ServeDir stripping the file extension when serving with identity encoding (#686)compression: forward trailers from the inner body after compression finishes, fixing dropped gRPC status trailers (#685)trace: fire on_eos when the inner body reports is_end_stream with a precise content-length (#687)on-early-drop: suppress the early-drop guard when is_end_stream is reported after a data frame (#687)set-header: make SetMultipleRequestHeaders and SetMultipleResponseHeaders Clone for non-Clone HTTP bodies (#703)set-header : add SetMultipleResponseHeadersLayer and SetMultipleResponseHeader for setting multiple response headers at once. Supports overriding , ap
set-header: add SetMultipleResponseHeadersLayer and
SetMultipleResponseHeader for setting multiple response headers at once.
Supports overriding, appending, and if_not_present modes. Header
values can be fixed or computed dynamically via closures (#672)
use http::{Response, header::{self, HeaderValue}};
use http_body::Body as _;
use tower_http::set_header::response::SetMultipleResponseHeadersLayer;
let layer = SetMultipleResponseHeadersLayer::overriding(vec![
(header::X_FRAME_OPTIONS, HeaderValue::from_static("DENY")).into(),
(header::CONTENT_LENGTH, |res: &Response<MyBody>| {
res.body().size_hint().exact()
.map(|size| HeaderValue::from_str(&size.to_string()).unwrap())
}).into(),
]);set-header: add SetMultipleRequestHeadersLayer and
SetMultipleRequestHeaders for setting multiple request headers at once,
mirroring the response-side API (#677)
classify: add From<i32> and From<NonZeroI32> impls for GrpcCode.
Unrecognized status codes map to GrpcCode::Unknown (#506)
compression: compress application/grpc-web responses. Previously allapplication/grpc* content types were excluded from compression; now onlyapplication/grpc (non-web) is excluded (#408)fs: fix ServeDir returning 500 instead of 405 for non-GET/HEAD requestscall_fallback_on_method_not_allowed is enabled but no fallback servicefs: remove duplicate cfg attribute on is_reserved_dos_name (#675)Full Changelog: tower-http-0.6.10...tower-http-0.6.11
follow-redirect : expose Attempt::method() and Attempt::previous_method() so redirect policies can react to method changes across redirects (e.g. POST
follow-redirect: expose Attempt::method() and Attempt::previous_method()tokio and async-compression as no-op features. These will beFull Changelog: tower-http-0.6.9...tower-http-0.6.10
doc: remove mention of deprecated bearer method in lib.rs comment by @VojtaStanek in #641
on-early-drop: middleware that detects when a response future or response
body is dropped before completion (#636)
Two events get hooks: the response future being dropped before
the inner service produces a response, and the response body being
dropped before reaching end-of-stream.
Install custom callbacks with OnEarlyDropLayer::builder():
use http::Request;
use tower_http::on_early_drop::{OnBodyDropFn, OnEarlyDropLayer};
let layer = OnEarlyDropLayer::builder()
.on_future_drop(|req: &Request<()>| {
let uri = req.uri().clone();
move || eprintln!("future dropped for {}", uri)
})
.on_body_drop(OnBodyDropFn::new(|req: &Request<()>| {
let uri = req.uri().clone();
move |parts: &http::response::Parts| {
let status = parts.status;
move || eprintln!("body dropped for {} status {}", uri, status)
}
}));Or route both events through a trace::OnFailure hook with
EarlyDropsAsFailures. Place this layer inside a TraceLayer so the
emitted events inherit the request span:
use tower::ServiceBuilder;
use tower_http::on_early_drop::{OnEarlyDropLayer, EarlyDropsAsFailures};
use tower_http::trace::{DefaultOnFailure, TraceLayer};
let stack = ServiceBuilder::new()
.layer(TraceLayer::new_for_http())
.layer(OnEarlyDropLayer::new(
EarlyDropsAsFailures::new(DefaultOnFailure::default()),
));fs: make AsyncReadBody::with_capacity public (#415)
async-compression feature is removed (#642)tokio feature is removed (#628)fs: no longer auto-enables the tracing crate feature; enable tracingServeDir IO failures (#614)trace: restore failure classification at end-of-stream (#483)follow-redirect: support unicode URLs (swaps iri-string dep forurl) (#646)fs: reject reserved Windows DOS device names (CON, COM1, etc.) inServeDir (#663)Full Changelog: tower-http-0.6.8...tower-http-0.6.9
Remove deprecated annotations and Refactor From implementations by @sinder38 in #608
multiple_members in Gzip decoder, since HTTP context only uses onemultiple_members option for gzip decoder by @ducaale in #621Full Changelog: tower-http-0.6.7...tower-http-0.6.8
TimeoutLayer::with_status_code(status) to define the status code returned when timeout is reached.
TimeoutLayer::with_status_code(status) to define the status code returnedauth::require_authorization is too basic for real-world. (#591)TimeoutLayer::new() should be replaced withTimeoutLayer::with_status_code(). (Previously wasStatusCode::REQUEST_TIMEOUT) (#599)on_eos is now called even for successful responses. (#580)ServeDir: call fallback when filename is invalid (#586)decompression will not fail when body is empty (#618)Full Changelog: tower-http-0.6.6...tower-http-0.6.7
compression: fix panic when looking in vary header
Full Changelog: tower-http-0.6.5...tower-http-0.6.6
normalize_path: add append_trailing_slash() mode
append_trailing_slash() mode (#547)vary: accept-encoding if already set (#572)Full Changelog: tower-http-0.6.4...tower-http-0.6.5
decompression: Support HTTP responses containing multiple ZSTD frames
ServiceExt trait for chaining layers onto an arbitrary http service justServiceBuilderExt allows for ServiceBuilder (#563)S::Error for Service impls ofRequestBodyTimeout<S> and ResponseBodyTimeout<S> (#533)is_end_stream (#535)fs::ServeDir (#553)content-lenght of 1 in response to range requests to emptyAsyncRequireAuthorization, use the original inner service after it isServiceExt trait for chaining layers onto an arbitrary http service just
like ServiceBuilderExt allows for ServiceBuilder (#563)S::Error for Service impls of
RequestBodyTimeout<S> and ResponseBodyTimeout<S> (#533)is_end_stream (#535)fs::ServeDir (#553)content-lenght of 1 in response to range requests to empty
files (#556)AsyncRequireAuthorization, use the original inner service after it is
ready, instead of using a clone (#561)This release was yanked because its definition of ServiceExt was quite unhelpful, in a way that's very unlikely that anybody would start depending on
This release was yanked because its definition of ServiceExt was quite unhelpful, in a way that's very unlikely that anybody would start depending on within the small timeframe before this was yanked, but that was technically breaking to change.
CompressionBody now propagates B's size hint in its http_body::Body implementation, if compression is disabled ([#531])
CompressionBody<B> now propagates B's size hint in its http_body::Body
implementation, if compression is disabled (#531)
content-length to be included in an HTTP message with this
body for those casesdecompression: reuse scratch buffer to significantly reduce allocations and improve performance ([#521])
body module is disabled except for catch-panic, decompression-*, fs, or limit features (BREAKING) ([#477])
compression: Will now send a vary: accept-encoding header on compressed responses ([#399])
vary: accept-encoding header on compressed responses (#399)x-gzip as equivalent to gzip in accept-encoding request header (#467)fs: Support files precompressed with zstd in ServeFile
Bump Minimum Supported Rust Version to 1.66 ([#433])
0.4Nothing published for this version
Nothing published for this version
cors: Add support for private network preflights ([#373])
request_id: Derive Default for MakeRequestUuid ([#335])
decompression: Add RequestDecompression middleware ([#282])
RequestDecompression middleware (#282)Default for CompressionBody (#323)ServeDir and ServeFile's error types are now Infallible and any IO errors
will be converted into responses. Use try_call to generate error responses manually (BREAKING) (#283)ServeDir::fallback and ServeDir::not_found_service now requires
the fallback service to use Infallible as its error type (BREAKING) (#283)RequireAuthorization in favor of ValidateRequest (BREAKING) (#290)Add NormalizePath middleware ([#275])
Add Timeout middleware ([#270])
serve_dir: Add ServeDir::call_fallback_on_method_not_allowed to allow calling the fallback for requests that aren't GET or HEAD ([#264])
ServeDir::call_fallback_on_method_not_allowed to allow calling the fallback
for requests that aren't GET or HEAD (#264)MakeRequestUuid for generating request ids using UUIDs (#266)Allow header for 405 Method Not Allowed responses (#263)serve_dir: Fix empty request parts being passed to ServeDir's fallback instead of the actual ones ([#258])
ServeDir's fallback instead of the actual ones (#258)cors: Only send a single origin in Access-Control-Allow-Origin header when a list of allowed origins is configured (the previous behavior of sending a
Access-Control-Allow-Origin header when a list of
allowed origins is configured (the previous behavior of sending a comma-separated list like for
allowed methods and allowed headers is not allowed by any standard)fs: Add ServeDir::{fallback, not_found_service} for calling another service if the file cannot be found ([#243])
ServeDir::{fallback, not_found_service} for calling another service if
the file cannot be found (#243)SetStatus to override status codes (#248)ServeDir and ServeFile now respond with 405 Method Not Allowed to requests where the
method isn't GET or HEAD (#249)CorsLayer::very_permissive which is like
CorsLayer::permissive except it (truly) allows credentials. This is made
possible by mirroring the request's origin as well as method and headers
back as CORS-whitelisted ones (#237)Vary header (#237)allow-credentials: true from CorsLayer::permissive.
It never actually took effect in compliant browsers because it is mutually
exclusive with the * wildcard (Any) on origins, methods and headers (#237)Any in
combination with .allow_credentials(true). This configuration worked
before, but resulted in browsers ignoring the allow-credentials header,
which defeats the purpose of setting it and can be very annoying to debug
(#237)Nothing published for this version
Added CatchPanic middleware which catches panics and converts them into 500 Internal Server responses ([#214])
Update to tokio-util 0.7 ([#221])
Add Vary headers for CORS preflight responses ([#216])
Vary headers for CORS preflight responses (#216)Support Last-Modified (and friends) headers in ServeDir and ServeFile ([#145])
builder: Add ServiceBuilderExt which adds methods to tower::ServiceBuilder for adding middleware from tower-http ([#106])
ServiceBuilderExt which adds methods to tower::ServiceBuilder for
adding middleware from tower-http (#106)SetRequestId and PropagateRequestId middleware (#150)DefaultMakeSpan::level to make log level of tracing spans easily configurable (#124)LatencyUnit::Seconds for formatting latencies as seconds (#179)GrpcErrorsAsFailures (#189)content-type, or something user defined (#172)Range requests (#173)Content-Length header set (#169)AddAuthorization, InFlightRequests, SetRequestHeader,
SetResponseHeader, AddExtension, MapRequestBody and MapResponseBody
now requires underlying service to use http::Request<ReqBody> and
http::Response<ResBody> as request and responses (#182) (BREAKING)SetRequestHeaderLayer
and SetResponseHeaderLayer. This removes the need (and possibility) to specify a
body type for these layers (#148) (BREAKING)Box<dyn std::error::Error + Send + Sync>. This makes them usable if
the body they're wrapping uses Box<dyn std::error::Error + Send + Sync> as
its error type which they previously weren't (#166) (BREAKING)ServeDir and ServeFile to
ServeFileSystemResponseBody and ServeFileSystemResponseFuture (#187) (BREAKING)AuthorizeRequest and AsyncAuthorizeRequest traits to be simpler (#192) (BREAKING)BodyOrIoError. Its been replaced with Box<dyn std::error::Error + Send + Sync> (#166) (BREAKING)compression and decompression feature. They were unnecessary
and compression-full/decompression-full can be used to get full
compression/decompression support. For more granular control, [compression|decompression]-gzip,
[compression|decompression]-br and [compression|decompression]-deflate may
be used instead (#170) (BREAKING)Nothing published for this version
New middleware: Add Cors for setting [CORS] headers ([#112])
Cors for setting [CORS] headers (#112)AsyncRequireAuthorization (#118)Compression: Don't recompress HTTP responses (#140)Compression and Decompression: Pass configuration from layer into middleware (#132)ServeDir and ServeFile: Improve performance (#137)Compression: Remove needless ResBody::Error: Into<BoxError> bounds (#117)ServeDir: Percent decode path segments (#129)ServeDir: Use correct redirection status (#130)ServeDir: Return 404 Not Found on requests to directories if
append_index_html_on_directories is set to false (#122)Add example of using SharedClassifier.
SharedClassifier.StatusInRangeAsFailures which is a response classifier that considers
responses with status code in a certain range as failures. Useful for HTTP
clients where both server errors (5xx) and client errors (4xx) are considered
failures.Debug for NeverClassifyEos.ClassifyResponse::map_failure_class and ClassifyEos::map_failure_class
for transforming the failure classification using a function.Trace callback is called.AddAuthorizationLayer for setting the Authorization header on
requests.[CORS]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →