Releases: tower-rs/tower-http
Release list
tower-http-0.7.0
Added
-
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: addDeadlineBodyfor non-resetting body timeouts, applied via the newRequestBodyDeadlineLayerandResponseBodyDeadlineLayer(#688)Unlike
TimeoutBody, which resets its deadline on every frame,DeadlineBodycaps 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 strongETagsupport toServeDir, includingIf-MatchandIf-None-Matchprecondition handling per RFC 9110.304 Not Modifiedresponses now carry theETagandLast-Modifiedvalidators (#691) -
fs: add aBackendtrait to makeServeDirwork with non-filesystem sources (e.g. embedded assets or object storage). The defaultTokioBackendpreserves existing behavior. UseServeDir::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: addhtml_as_default_extensionoption toServeDir, appending.htmlwhen the request path has no extension (#519) -
fs: addredirect_path_prefixoption toServeDir, prepending a prefix on trailing-slash redirects so the service can be mounted under a sub-path (#486) -
validate-request: addValidateRequestHeaderLayer::has_header_value()to reject requests when a header does not have an expected value (#360) -
body:UnsyncBoxBody::new()constructor andFrom<ServeFileSystemResponseBody>conversion to avoid double-boxing when combiningServeDirresponses with other body types (#537) -
limit: implementDefaultforlimit::ResponseBodywhen the wrapped body also implementsDefault(#679)
Changed
-
breaking:
compression: the middleware now handles the*wildcard andidentity;q=0in Accept-Encoding per RFC 9110 §12.5.3. Requests that previously fell back to identity (e.g.*;q=0oridentity;q=0with 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 theSizeAbovepredicate threshold fromu16tou64, allowing minimum sizes above 64 KiB (#704) -
breaking: remove the implicit no-op
tokioandasync-compressionfeatures. These were kept as no-op features in 0.6.x for backwards compatibility after the switch todep:syntax in #642. Downstream crates that activatetower-http/tokioortower http/async-compressionshould 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.GrpcCodeandGrpcFailureClassare now#[non_exhaustive], andGrpcStatusis exported from theclassifymodule (#422) -
breaking:
follow-redirect:FollowRedirectnow forwards requestExtensionsto redirected requests instead of dropping them. TheStandardpolicy drops extensions on cross-origin redirections (same-origin keeps them). Opt out withFollowRedirectLayer::preserve_extensions(false); keep specific types withFilterCredentials::allow_extension::<T>()or all of them withkeep_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, soFilterCredentialsno longer re-sendsCookie/Authorizationto a same-origin target reached after cross-origin hop. CustomPolicy::on_requestimpls now see the previous hop's filtered request, not the original. (#706) -
trace:DefaultOnRequest,DefaultOnResponse,DefaultOnFailure, andDefaultOnEosnow 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 theVaryheader defaults (#674) -
MSRV bumped from 1.64 to 1.65 (#684)
Fixed
fs:ServeDirandServeFilenow emit aVary: Accept-Encodingresponse
header when precompressed serving is configured, ensuring caches correctly
distinguish between compressed and uncompressed variants (#692)- breaking:
services: reject a trailing slash for file paths. File requests with a trailing slash now return404 Not Foundinstead of serving the file (#678) fs: fixServeDirstripping 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: fireon_eoswhen the inner body reportsis_end_streamwith a precise content-length (#687)on-early-drop: suppress the early-drop guard whenis_end_streamis reported after a data frame (#687)set-header: makeSetMultipleRequestHeadersandSetMultipleResponseHeadersClonefor non-CloneHTTP bodies (#703)
Thanks
New Contributors
- @muhamadazmy made their first contribution in #679
- @Isvane made their first contribution in #678
- @xiaoyawei made their first contribution in #422
- @dependabot[bot] made their first contribution in #696
- @its-the-shrimp made their first contribution in #519
- @yawn made their first contribution in #699
- @Jesse-Bakker made their first contribution in #703
- @junghwan16 made their first contribution in #705
- @claraphyll made their first contribution in #486
tower-http-0.6.11
Added
-
set-header: addSetMultipleResponseHeadersLayerand
SetMultipleResponseHeaderfor setting multiple response headers at once.
Supportsoverriding,appending, andif_not_presentmodes. 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: addSetMultipleRequestHeadersLayerand
SetMultipleRequestHeadersfor setting multiple request headers at once,
mirroring the response-side API (#677) -
classify: addFrom<i32>andFrom<NonZeroI32>impls forGrpcCode.
Unrecognized status codes map toGrpcCode::Unknown(#506)
Changed
compression: compressapplication/grpc-webresponses. Previously all
application/grpc*content types were excluded from compression; now only
application/grpc(non-web) is excluded (#408)
Fixed
fs: fixServeDirreturning 500 instead of 405 for non-GET/HEAD requests
whencall_fallback_on_method_not_allowedis enabled but no fallback service
is configured (#587)fs: remove duplicatecfgattribute onis_reserved_dos_name(#675)
All PRs
- ci: fix flaky encoding test, add nightly stress test job by @jlizen in #670
- ci: use static timeout in stress-test workflow by @jlizen in #671
- Fix serve_dir method not allowed handling when no fallback is configured by @soerenmeier in #587
- Do compress grpc-web responses by @bouk in #408
- add From impl for GrpcCode by @gshipilov in #506
- feat(set_header): refactor and improve multiple header middleware by @seun-ja in #672
- Remove duplicate cfg attribute for is_reserved_dos_name by @GlenDC in #675
- feat: set multiple request header by @seun-ja in #677
- chore: release 0.6.11 by @jlizen in #673
New Contributors
- @gshipilov made their first contribution in #506
- @seun-ja made their first contribution in #672
Full Changelog: tower-http-0.6.10...tower-http-0.6.11
tower-http-0.6.10
Added
follow-redirect: exposeAttempt::method()andAttempt::previous_method()
so redirect policies can react to method changes across redirects (e.g.
POST to GET on 301/303) (#559)
Fixed
- Restore
tokioandasync-compressionas no-op features. These will be
removed next breaking release (#667)
What's Changed
- fix: restore tokio and async-compression as no-op features by @jlizen in #667
- fix gate-ing of atomic64 in tests by @alexanderkjall in #607
- follow_redirect: expose previous and next request methods by @lucab in #559
- chore: release tower-http 0.6.10 by @jlizen in #669
New Contributors
Full Changelog: tower-http-0.6.9...tower-http-0.6.10
tower-http-0.6.9
Added:
-
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::OnFailurehook with
EarlyDropsAsFailures. Place this layer inside aTraceLayerso 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: makeAsyncReadBody::with_capacitypublic (#415)
Changed:
- The implicit
async-compressionfeature is removed (#642) - The implicit
tokiofeature is removed (#628) fs: no longer auto-enables thetracingcrate feature; enabletracing
explicitly to restore error logging onServeDirIO failures (#614)
Fixed
trace: restore failure classification at end-of-stream (#483)follow-redirect: support unicode URLs (swapsiri-stringdep for
url) (#646)fs: reject reserved Windows DOS device names (CON,COM1, etc.) in
ServeDir(#663)
All the PRs
- ci: update deny action to v2 by @seanmonstar in #627
- chore: improve code comments clarity by @xibeiyoumian in #626
- ci: Update to actions/checkout v6 by @tottoto in #629
- ci: msrv resolver by @seanmonstar in #635
- chore: Remove resolved cargo-deny config by @tottoto in #631
- ci: Update to cargo-check-external-types 0.4.0 by @tottoto in #633
- examples: Use typed default value clap config by @tottoto in #634
- examples: Disable unused reqwest feature by @tottoto in #632
- examples: Update to reqwest 0.13 by @tottoto in #640
- Fix clippy warnings in warp-key-value-store example by @jplatte in #637
- ci: Use Swatinem/rust-cache@v2 to cache by @tottoto in #644
- ci: Remove unused working-directory config by @tottoto in #645
- Use cargo-deny graph config by @tottoto in #639
- Fix: follow redirect unicode in #646
- doc: remove mention of deprecated bearer method in lib.rs comment by @VojtaStanek in #641
- Allow Unicode-3.0 license by @tottoto in #648
- fix(docs): typo by @carlocorradini in #649
- fix: remove unused GzEncoder import in decompression in #647
- docs: update Example server in #652
- Don't automatically enable tracing for fs feature by @ginnyTheCat in #614
- examples: Remove unnecessary trait bound by @tottoto in #651
- Remove implicit async-compression feature by @tottoto in #642
- fix clippy warnings by @alexanderkjall in #659
- Check for reserved DOS names by @Darksonn in #663
- enable clippy for tower-http and fix current issues by @GlenDC in #407
- chore: remove implicit tokio feature by @WaterWhisperer in #628
- trace: adds back call to classify_eos on trailers by @markdingram in #483
- Make AsyncReadBody::with_capacity public by @bouk in #415
- examples: Use axum::body::to_bytes by @tottoto in #650
- ci: Remove unnecessary protoc setup by @tottoto in #665
- feat(on-early-drop): Add middleware for client early drop detection by @fbergero in #636
- chore: release tower-http 0.6.9 by @jlizen in #666
New Contributors
- @xibeiyoumian made their first contribution in #626
- @VojtaStanek made their first contribution in #641
- @carlocorradini made their first contribution in #649
- @ginnyTheCat made their first contribution in #614
- @alexanderkjall made their first contribution in #659
- @Darksonn made their first contribution in #663
- @WaterWhisperer made their first contribution in #628
- @bouk made their first contribution in #415
- @fbergero made their first contribution in #636
- @jlizen made their first contribution in #666
Full Changelog: tower-http-0.6.8...tower-http-0.6.9
tower-http-0.6.8
Fixed
- Disable
multiple_membersin Gzip decoder, since HTTP context only uses one
member. (#621)
What's Changed
- Disable
multiple_membersoption for gzip decoder by @ducaale in #621 - ci: Pin tracing in MSRV job by @ducaale in #622
- ci: Switch cargo-public-api-crates to cargo-check-external-types by @tottoto in #613
- Remove deprecated annotations and Refactor From implementations by @sinder38 in #608
- v0.6.8 by @seanmonstar in #624
New Contributors
Full Changelog: tower-http-0.6.7...tower-http-0.6.8
tower-http-0.6.7
Added
TimeoutLayer::with_status_code(status)to define the status code returned
when timeout is reached. (#599)
Deprecated
auth::require_authorizationis too basic for real-world. (#591)TimeoutLayer::new()should be replaced with
TimeoutLayer::with_status_code(). (Previously was
StatusCode::REQUEST_TIMEOUT) (#599)
Fixed
on_eosis now called even for successful responses. (#580)ServeDir: call fallback when filename is invalid (#586)decompressionwill not fail when body is empty (#618)
New Contributors
- @mladedav made their first contribution in #580
- @aryaveersr made their first contribution in #586
- @soerenmeier made their first contribution in #588
- @gjabell made their first contribution in #591
- @FalkWoldmann made their first contribution in #599
- @ducaale made their first contribution in #618
Full Changelog: tower-http-0.6.6...tower-http-0.6.7
tower-http-0.6.6
Fixed
- compression: fix panic when looking in vary header (#578)
New Contributors
Full Changelog: tower-http-0.6.5...tower-http-0.6.6
tower-http-0.6.5
Added
- normalize_path: add
append_trailing_slash()mode (#547)
Fixed
- redirect: remove payload headers if redirect changes method to GET (#575)
- compression: avoid setting
vary: accept-encodingif already set (#572)
New Contributors
- @daalfox made their first contribution in #547
- @mherrerarendon made their first contribution in #574
- @linyihai made their first contribution in #575
Full Changelog: tower-http-0.6.4...tower-http-0.6.5
tower-http 0.6.4
Added
- decompression: Support HTTP responses containing multiple ZSTD frames (#548)
- The
ServiceExttrait for chaining layers onto an arbitrary http service just
likeServiceBuilderExtallows forServiceBuilder(#563)
Fixed
- Remove unnecessary trait bounds on
S::ErrorforServiceimpls of
RequestBodyTimeout<S>andResponseBodyTimeout<S>(#533) - compression: Respect
is_end_stream(#535) - Fix a rare panic in
fs::ServeDir(#553) - Fix invalid
content-lenghtof 1 in response to range requests to empty
files (#556) - In
AsyncRequireAuthorization, use the original inner service after it is
ready, instead of using a clone (#561)
tower-http 0.6.3
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.