Skip to content

v0.94.0

Latest

Choose a tag to compare

@github-actions github-actions released this 07 Jul 02:38

v0.94.0

Salvo 0.94.0 focuses on security hardening, OpenAPI 3.1 correctness, lower runtime overhead in core routing/dispatch paths, and API naming cleanup. This release also raises the Rust MSRV to 1.94.

Highlights

  • Rust MSRV is now 1.94.
  • Core routing and dispatch were reworked to reduce per-request allocations and improve path parameter rollback.
  • Server lifecycle control is clearer, with Server::max_connections, ConnCtrl, improved graceful/forceful shutdown behavior, and safer default connection fuse protection.
  • OpenAPI generation is closer to OpenAPI 3.1: jsonSchemaDialect, webhooks, reusable components, PathItem refs, parameter content/examples/allowEmptyValue, and stricter required path parameters.
  • Security hardening landed across proxying, CORS, CSRF, static files, default error pages, JWT/OIDC, WebSocket upgrades, tus uploads, cookies, and ACME.
  • Response rendering semantics are documented and tightened: text-like scribes append, while Json<T> now replaces previously buffered body bytes because JSON is a complete document.
  • salvo-tus exposes storage/locking types, adds Tus::storage_root, and adds Tus::absolute_location for safe absolute Location URLs.

Migration Guide

Rust

Update your toolchain to Rust 1.94 or newer.

rustup update stable

Core API naming

Several old names remain as deprecated aliases, but new code should use the clearer names:

Old New
Depot::inject(value) Depot::insert_typed(value)
Depot::obtain::<T>() Depot::get_typed::<T>()
Depot::obtain_mut::<T>() Depot::get_typed_mut::<T>()
Depot::contains::<T>() Depot::contains_typed::<T>()
Depot::scrape::<T>() Depot::remove_typed::<T>()
Depot::delete(key) Depot::remove(key).is_some()
Response::stuff(status, value) Response::render_with_status(status, value)
Server::stop_forcible() Server::stop_forceful()
ServerHandle::stop_forcible() ServerHandle::stop_forceful()
SchemeFilter::lack(...) SchemeFilter::fallback(...)
HostFilter::lack(...) HostFilter::fallback(...)
PortFilter::lack(...) PortFilter::fallback(...)
StatusError::request_header_fields_toolarge() StatusError::request_header_fields_too_large()
StatusError::unavailable_for_legalreasons() StatusError::unavailable_for_legal_reasons()
AcmeListener::get_directory(...) AcmeListener::directory(...)

Depot now has separate named and type-keyed storage. Use insert/get/remove for string keys and insert_typed/get_typed/remove_typed for type keys. Capacity and inner() refer to named storage.

Response body rendering

Response::write_body appends to buffered bodies. Json<T> now replaces existing buffered bytes instead of appending, because concatenated JSON documents are invalid. If you intentionally emit NDJSON or another appendable format, serialize each record yourself and call write_body.

salvo-tus builder methods

The tus builder API was aligned with Rust API naming guidelines. Update call sites:

Old New
with_store(...) store(...)
with_locker(...) locker(...)
with_upload_id_naming_function(...) upload_id_naming_function(...)
with_generate_url_function(...) generate_url_function(...)
with_on_incoming_request(...) on_incoming_request(...)
with_on_incoming_request_sync(...) on_incoming_request_sync(...)
with_on_upload_create(...) on_upload_create(...)
with_on_upload_finish(...) on_upload_finish(...)

Also prefer MaybeUploadId over the deprecated UploadId alias. TusOptions::extract_file_id_from_request replaces the old file-id helper naming.

For absolute tus Location headers, prefer:

let tus = Tus::new().absolute_location("https://uploads.example.com");

Avoid relative_location(false) without a canonical origin on public services, because that derives absolute URLs from request host/forwarded headers.

OpenAPI changes

  • Top-level $schema output was corrected to jsonSchemaDialect for OpenAPI 3.1.
  • Parameter::parameter_in(...) is deprecated; use Parameter::location(...).
  • ToParameters now defaults generated parameters to query location, so required query parameters are represented correctly.
  • Path parameters are now always serialized as required: true.
  • Routes without an HTTP method filter are skipped during OpenAPI generation instead of being fanned out to every method.
  • #[derive(Extractible)] now rejects #[serde(flatten)] on fields. Use #[salvo(extract(flatten))] for Salvo request extraction flattening.

CORS, proxy, JWT/OIDC, and cookies

  • CORS now rejects or strips unsafe combinations of Access-Control-Allow-Credentials: true with wildcard CORS response headers. Use explicit allowed origins, headers, and methods for credentialed APIs.
  • ForwardedHeaderIssuer is deprecated because it trusts client-controlled forwarded headers unconditionally. Use TrustedProxyIssuer::new([...]) behind known proxies, or RemoteIpIssuer for direct client IPs.
  • Proxy now uses the standards-compliant host header getter by default, including non-default upstream ports. If you need the old bare-host behavior, configure default_host_header_getter.
  • OIDC JWKS symmetric keys (kty: "oct" / HS*) are rejected by default. Opt in with allow_symmetric_jwks(true) only for issuers that intentionally publish trusted symmetric keys.
  • SecureCookiePolicy is available for CSRF, flash, and session cookies. If TLS terminates before Salvo and the request scheme appears as HTTP, force secure cookies with the relevant secure_cookie(true) or policy API.

Notable Changes

Core and server

  • Added Server::max_connections to bound concurrent accepted connections.
  • Reworked connection protection, lifecycle control, and router matching for lower overhead and clearer shutdown behavior.
  • Added ConnCtrl to the prelude and public exports.
  • Improved routing parameter rollback, wildcard capture handling, host/port filtering for IPv6, and matched-path handling.
  • Added response render API clarity and deprecated awkward or misleading names.

OpenAPI

  • Completed several OpenAPI 3.1 reusable component types.
  • Added top-level webhooks and PathItem $ref support.
  • Added Parameter Object content, examples, and allowEmptyValue.
  • Fixed schema generation for inline generic schemas, request body refs, generic Extractible bounds, number equality, macro diagnostics, and several user-triggerable macro panics.
  • Added endpoint attribute aliases and accepted singular/plural parameter keys interchangeably.

Security hardening

  • Escaped the default error page and Swagger UI/static directory generated output to reduce reflected XSS risk.
  • Switched CSRF token verification to constant-time comparison.
  • Hardened proxy path normalization, upgrade handling, host headers, body error propagation, and optional authorization forwarding.
  • Added WebSocket Origin checking APIs to mitigate CSWSH on cookie-authenticated WebSocket endpoints.
  • Hardened StaticDir root boundary checks and precompressed file handling.
  • Tightened tus CORS handling, upload id validation, expiration handling, offset overflow checks, finalized-file protection, and absolute Location URL guidance.
  • Bounded OIDC/JWKS fetch sizes and cache behavior, improved OIDC revalidation races, and avoided leaking sensitive panic/error payloads.
  • Added safer secure-cookie policy handling for session, flash, and CSRF cookies.

Fixes

  • Fixed Set-Cookie parsing/round-tripping and tower-compatible response conversion.
  • Fixed cache behavior that could swallow requests or cache non-success responses.
  • Fixed conditional request ordering, multi-range response handling, IPv6 authority parsing, ETag formatting, and range streaming.
  • Fixed multipart parsing edge cases, missing boundary handling, file-part detection, temp-file cleanup, and panic paths.
  • Fixed sliding-window rate limiting and normalized quota behavior.
  • Fixed OIDC HTTP/2 negotiation and clock-skew panic paths.
  • Fixed RequestId, caching headers, basic auth multi-header fallthrough, and logging path/address behavior.
  • Fixed multiple tus protocol and storage edge cases.

Performance

  • Reduced allocations in routing/path matching, WebSocket upgrade, proxy path encoding, JSON response rendering, CORS header joining, compression Accept-Encoding parsing, Accept parsing, text_nonce, and write_body.
  • Added a pass-through hasher for Depot type-keyed storage.
  • Bounded cache in-flight miss coalescing and improved sliding-window rate limiter bookkeeping.
  • Added criterion benchmarks for routing and dispatch hot paths.

Contributors

Thanks to everyone who contributed to this release:

New Contributors

Full Changelog: v0.93.0...v0.94.0