tower-http-0.7.1
fs: addServeDir::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: addignore_multi_range_requests()toServeDirandServeFile, serving the full representation when a request asks for multiple byte ranges. The existing416 Range Not Satisfiableresponse remains the default (#727)request-id: the constructors and accessors on the request-id layers, services, andRequestIdare nowconst fn, so they can be used in const context (#716)
fs: the minimumhttp-range-headerrequirement is now 0.4.2 (#661)
- behavioral change:
fs: makeServeDir::try_callpropagate expected filesystem I/O errors when no fallback is configured, as documented, instead of converting them to404 Not Foundresponses (#718) decompression: don't end the body when a data frame with no remaining bytes arrives after the decompressor reports end-of-stream. Trailers following such a frame were dropped and could not be recovered (#722)decompression: return a body error when a data frame with remaining bytes arrives after the decompressor reports end-of-stream, rather than silently truncating. This regressed in 0.7.0 (#712)fs: multipart range requests are now rejected before range validation, so they consistently return416 Range Not Satisfiablewith aCannot serve multipart range requestsbody instead of a generic unsatisfiable-range response (#661)fs: range error responses no longer carry representation headers such asContent-TypeandContent-Encoding(#727)set-header:SetMultipleResponseHeadersLayerandSetMultipleResponseHeaderare nowCloneregardless of the response body type, matching the fix applied to the request-side types in 0.7.0 (#714)
- chore(deps): bump actions/checkout from 6 to 7 by @dependabot[bot] in https://github.com/tower-rs/tower-http/pull/708
- fix(compression): reject non-empty data frames after codec is EOF by @seanmonstar in https://github.com/tower-rs/tower-http/pull/712
- Remove Clone derivations from SetMultipleResponseHeader* types by @skeet70 in https://github.com/tower-rs/tower-http/pull/714
- feat(request-id): Allow request-id constructor in const context by @tottoto in https://github.com/tower-rs/tower-http/pull/716
- fs: Avoid unnecessary conversions between SystemTime and HttpDate by @tottoto in https://github.com/tower-rs/tower-http/pull/717
- fs: Use HeaderValue::is_empty to check for empty values by @tottoto in https://github.com/tower-rs/tower-http/pull/720
- fs: Use HeaderValue::to_str for date headers by @tottoto in https://github.com/tower-rs/tower-http/pull/721
- chore(deps): bump taiki-e/install-action from 2 to 2.85.4 by @dependabot[bot] in https://github.com/tower-rs/tower-http/pull/715
- chore(deps): bump taiki-e/install-action from 2.85.4 to 2.85.12 by @dependabot[bot] in https://github.com/tower-rs/tower-http/pull/723
- docs(example)/custom future with multiple bodies by @Reza-Darius in https://github.com/tower-rs/tower-http/pull/711
- fix(decompression): don't end the body on an empty data frame by @clemenslosbichler-cloud in https://github.com/tower-rs/tower-http/pull/722
- Propagate ServeDir::try_call I/O errors by @Boulea7 in https://github.com/tower-rs/tower-http/pull/718
- ci: Update to cargo-check-external-types 0.5.0 by @tottoto in https://github.com/tower-rs/tower-http/pull/724
- fix: reject multipart ranges before validation by @shblue21 in https://github.com/tower-rs/tower-http/pull/661
- chore(deps): bump taiki-e/install-action from 2.85.12 to 2.86.3 by @dependabot[bot] in https://github.com/tower-rs/tower-http/pull/726
- feat(services): configure directory redirects by @BreezeDelegate in https://github.com/tower-rs/tower-http/pull/728
- Allow ignoring unsupported multi-range requests by @BreezeDelegate in https://github.com/tower-rs/tower-http/pull/727
- chore(deps): bump taiki-e/install-action from 2.86.3 to 2.86.8 by @dependabot[bot] in https://github.com/tower-rs/tower-http/pull/730
- chore(release): prepare 0.7.1 by @jlizen in https://github.com/tower-rs/tower-http/pull/729
- @skeet70 made their first contribution in https://github.com/tower-rs/tower-http/pull/714
- @Reza-Darius made their first contribution in https://github.com/tower-rs/tower-http/pull/711
- @clemenslosbichler-cloud made their first contribution in https://github.com/tower-rs/tower-http/pull/722
- @Boulea7 made their first contribution in https://github.com/tower-rs/tower-http/pull/718
- @shblue21 made their first contribution in https://github.com/tower-rs/tower-http/pull/661
- @BreezeDelegate made their first contribution in https://github.com/tower-rs/tower-http/pull/728
tower-http-0.7.0
-
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)
-
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)
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)
- @jlizen
- @seun-ja
- @Oliboy50
- @muhamadazmy made their first contribution in https://github.com/tower-rs/tower-http/pull/679
- @Isvane made their first contribution in https://github.com/tower-rs/tower-http/pull/678
- @xiaoyawei made their first contribution in https://github.com/tower-rs/tower-http/pull/422
- @dependabot[bot] made their first contribution in https://github.com/tower-rs/tower-http/pull/696
- @its-the-shrimp made their first contribution in https://github.com/tower-rs/tower-http/pull/519
- @yawn made their first contribution in https://github.com/tower-rs/tower-http/pull/699
- @Jesse-Bakker made their first contribution in https://github.com/tower-rs/tower-http/pull/703
- @junghwan16 made their first contribution in https://github.com/tower-rs/tower-http/pull/705
- @claraphyll made their first contribution in https://github.com/tower-rs/tower-http/pull/486
tower-http-0.6.11
-
set-header: addSetMultipleResponseHeadersLayerandSetMultipleResponseHeaderfor 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: addSetMultipleRequestHeadersLayerandSetMultipleRequestHeadersfor 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)
compression: compressapplication/grpc-webresponses. Previously allapplication/grpc*content types were excluded from compression; now onlyapplication/grpc(non-web) is excluded (#408)
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)
- ci: fix flaky encoding test, add nightly stress test job by @jlizen in https://github.com/tower-rs/tower-http/pull/670
- ci: use static timeout in stress-test workflow by @jlizen in https://github.com/tower-rs/tower-http/pull/671
- Fix serve_dir method not allowed handling when no fallback is configured by @soerenmeier in https://github.com/tower-rs/tower-http/pull/587
- Do compress grpc-web responses by @bouk in https://github.com/tower-rs/tower-http/pull/408
- add From impl for GrpcCode by @gshipilov in https://github.com/tower-rs/tower-http/pull/506
- feat(set_header): refactor and improve multiple header middleware by @seun-ja in https://github.com/tower-rs/tower-http/pull/672
- Remove duplicate cfg attribute for is_reserved_dos_name by @GlenDC in https://github.com/tower-rs/tower-http/pull/675
- feat: set multiple request header by @seun-ja in https://github.com/tower-rs/tower-http/pull/677
- chore: release 0.6.11 by @jlizen in https://github.com/tower-rs/tower-http/pull/673
- @gshipilov made their first contribution in https://github.com/tower-rs/tower-http/pull/506
- @seun-ja made their first contribution in https://github.com/tower-rs/tower-http/pull/672
Full Changelog: https://github.com/tower-rs/tower-http/compare/tower-http-0.6.10...tower-http-0.6.11
tower-http-0.6.10
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)
- Restore
tokioandasync-compressionas no-op features. These will be removed next breaking release (#667)
- fix: restore tokio and async-compression as no-op features by @jlizen in https://github.com/tower-rs/tower-http/pull/667
- fix gate-ing of atomic64 in tests by @alexanderkjall in https://github.com/tower-rs/tower-http/pull/607
- follow_redirect: expose previous and next request methods by @lucab in https://github.com/tower-rs/tower-http/pull/559
- chore: release tower-http 0.6.10 by @jlizen in https://github.com/tower-rs/tower-http/pull/669
- @lucab made their first contribution in https://github.com/tower-rs/tower-http/pull/559
Full Changelog: https://github.com/tower-rs/tower-http/compare/tower-http-0.6.9...tower-http-0.6.10
tower-http-0.6.9
-
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 withEarlyDropsAsFailures. 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)
- The implicit
async-compressionfeature is removed (#642) - The implicit
tokiofeature is removed (#628) fs: no longer auto-enables thetracingcrate feature; enabletracingexplicitly to restore error logging onServeDirIO failures (#614)
trace: restore failure classification at end-of-stream (#483)follow-redirect: support unicode URLs (swapsiri-stringdep forurl) (#646)fs: reject reserved Windows DOS device names (CON,COM1, etc.) inServeDir(#663)
- ci: update deny action to v2 by @seanmonstar in https://github.com/tower-rs/tower-http/pull/627
- chore: improve code comments clarity by @xibeiyoumian in https://github.com/tower-rs/tower-http/pull/626
- ci: Update to actions/checkout v6 by @tottoto in https://github.com/tower-rs/tower-http/pull/629
- ci: msrv resolver by @seanmonstar in https://github.com/tower-rs/tower-http/pull/635
- chore: Remove resolved cargo-deny config by @tottoto in https://github.com/tower-rs/tower-http/pull/631
- ci: Update to cargo-check-external-types 0.4.0 by @tottoto in https://github.com/tower-rs/tower-http/pull/633
- examples: Use typed default value clap config by @tottoto in https://github.com/tower-rs/tower-http/pull/634
- examples: Disable unused reqwest feature by @tottoto in https://github.com/tower-rs/tower-http/pull/632
- examples: Update to reqwest 0.13 by @tottoto in https://github.com/tower-rs/tower-http/pull/640
- Fix clippy warnings in warp-key-value-store example by @jplatte in https://github.com/tower-rs/tower-http/pull/637
- ci: Use Swatinem/rust-cache@v2 to cache by @tottoto in https://github.com/tower-rs/tower-http/pull/644
- ci: Remove unused working-directory config by @tottoto in https://github.com/tower-rs/tower-http/pull/645
- Use cargo-deny graph config by @tottoto in https://github.com/tower-rs/tower-http/pull/639
- Fix: follow redirect unicode in https://github.com/tower-rs/tower-http/pull/646
- doc: remove mention of deprecated bearer method in lib.rs comment by @VojtaStanek in https://github.com/tower-rs/tower-http/pull/641
- Allow Unicode-3.0 license by @tottoto in https://github.com/tower-rs/tower-http/pull/648
- fix(docs): typo by @carlocorradini in https://github.com/tower-rs/tower-http/pull/649
- fix: remove unused GzEncoder import in decompression in https://github.com/tower-rs/tower-http/pull/647
- docs: update Example server in https://github.com/tower-rs/tower-http/pull/652
- Don't automatically enable tracing for fs feature by @ginnyTheCat in https://github.com/tower-rs/tower-http/pull/614
- examples: Remove unnecessary trait bound by @tottoto in https://github.com/tower-rs/tower-http/pull/651
- Remove implicit async-compression feature by @tottoto in https://github.com/tower-rs/tower-http/pull/642
- fix clippy warnings by @alexanderkjall in https://github.com/tower-rs/tower-http/pull/659
- Check for reserved DOS names by @Darksonn in https://github.com/tower-rs/tower-http/pull/663
- enable clippy for tower-http and fix current issues by @GlenDC in https://github.com/tower-rs/tower-http/pull/407
- chore: remove implicit tokio feature by @WaterWhisperer in https://github.com/tower-rs/tower-http/pull/628
- trace: adds back call to classify_eos on trailers by @markdingram in https://github.com/tower-rs/tower-http/pull/483
- Make AsyncReadBody::with_capacity public by @bouk in https://github.com/tower-rs/tower-http/pull/415
- examples: Use axum::body::to_bytes by @tottoto in https://github.com/tower-rs/tower-http/pull/650
- ci: Remove unnecessary protoc setup by @tottoto in https://github.com/tower-rs/tower-http/pull/665
- feat(on-early-drop): Add middleware for client early drop detection by @fbergero in https://github.com/tower-rs/tower-http/pull/636
- chore: release tower-http 0.6.9 by @jlizen in https://github.com/tower-rs/tower-http/pull/666
- @xibeiyoumian made their first contribution in https://github.com/tower-rs/tower-http/pull/626
- @VojtaStanek made their first contribution in https://github.com/tower-rs/tower-http/pull/641
- @carlocorradini made their first contribution in https://github.com/tower-rs/tower-http/pull/649
- @ginnyTheCat made their first contribution in https://github.com/tower-rs/tower-http/pull/614
- @alexanderkjall made their first contribution in https://github.com/tower-rs/tower-http/pull/659
- @Darksonn made their first contribution in https://github.com/tower-rs/tower-http/pull/663
- @WaterWhisperer made their first contribution in https://github.com/tower-rs/tower-http/pull/628
- @bouk made their first contribution in https://github.com/tower-rs/tower-http/pull/415
- @fbergero made their first contribution in https://github.com/tower-rs/tower-http/pull/636
- @jlizen made their first contribution in https://github.com/tower-rs/tower-http/pull/666
Full Changelog: https://github.com/tower-rs/tower-http/compare/tower-http-0.6.8...tower-http-0.6.9
tower-http-0.6.8
- Disable
multiple_membersin Gzip decoder, since HTTP context only uses one member. (#621)
- Disable
multiple_membersoption for gzip decoder by @ducaale in https://github.com/tower-rs/tower-http/pull/621 - ci: Pin tracing in MSRV job by @ducaale in https://github.com/tower-rs/tower-http/pull/622
- ci: Switch cargo-public-api-crates to cargo-check-external-types by @tottoto in https://github.com/tower-rs/tower-http/pull/613
- Remove deprecated annotations and Refactor From implementations by @sinder38 in https://github.com/tower-rs/tower-http/pull/608
- v0.6.8 by @seanmonstar in https://github.com/tower-rs/tower-http/pull/624
- @sinder38 made their first contribution in https://github.com/tower-rs/tower-http/pull/608
Full Changelog: https://github.com/tower-rs/tower-http/compare/tower-http-0.6.7...tower-http-0.6.8
tower-http-0.6.7
TimeoutLayer::with_status_code(status)to define the status code returned when timeout is reached. (#599)
auth::require_authorizationis too basic for real-world. (#591)TimeoutLayer::new()should be replaced withTimeoutLayer::with_status_code(). (Previously wasStatusCode::REQUEST_TIMEOUT) (#599)
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)
- @mladedav made their first contribution in https://github.com/tower-rs/tower-http/pull/580
- @aryaveersr made their first contribution in https://github.com/tower-rs/tower-http/pull/586
- @soerenmeier made their first contribution in https://github.com/tower-rs/tower-http/pull/588
- @gjabell made their first contribution in https://github.com/tower-rs/tower-http/pull/591
- @FalkWoldmann made their first contribution in https://github.com/tower-rs/tower-http/pull/599
- @ducaale made their first contribution in https://github.com/tower-rs/tower-http/pull/618
Full Changelog: https://github.com/tower-rs/tower-http/compare/tower-http-0.6.6...tower-http-0.6.7
tower-http-0.6.6
- compression: fix panic when looking in vary header (#578)
- @sulami made their first contribution in https://github.com/tower-rs/tower-http/pull/578
Full Changelog: https://github.com/tower-rs/tower-http/compare/tower-http-0.6.5...tower-http-0.6.6
tower-http-0.6.5
- normalize_path: add
append_trailing_slash()mode (#547)
- redirect: remove payload headers if redirect changes method to GET (#575)
- compression: avoid setting
vary: accept-encodingif already set (#572)
- @daalfox made their first contribution in https://github.com/tower-rs/tower-http/pull/547
- @mherrerarendon made their first contribution in https://github.com/tower-rs/tower-http/pull/574
- @linyihai made their first contribution in https://github.com/tower-rs/tower-http/pull/575
Full Changelog: https://github.com/tower-rs/tower-http/compare/tower-http-0.6.4...tower-http-0.6.5
tower-http 0.6.4
- decompression: Support HTTP responses containing multiple ZSTD frames (#548)
- The
ServiceExttrait for chaining layers onto an arbitrary http service just likeServiceBuilderExtallows forServiceBuilder(#563)
- Remove unnecessary trait bounds on
S::ErrorforServiceimpls ofRequestBodyTimeout<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)