A powerful web framework built with a simplified design.
  • JavaScript 50%
  • Rust 49.9%
  • Shell 0.1%
Find a file
Emrul Islam 0e8477c107
WebTransport interop with ratified-era clients (Safari/WebKit NF)
The vendored h3 speaks draft-02 WebTransport only; Apple's Network.framework
client (Safari 26.4+ on macOS 26 / iPadOS 26) speaks the ratified drafts and
silently cancels the extended CONNECT against a draft-02-only server. A/B'd
live against Safari/NF:

- Advertise the later-draft SETTINGS alongside draft-02:
  WT_MAX_SESSIONS 0x14e9cd29 (draft-10+) and 0xc671706a (draft-07..09 —
  Apple keys on THIS one; omitting it cancels the session). Unknown settings
  are ignored per RFC 9114 so draft-02 clients (Chrome) are unaffected.
- Do NOT advertise the draft-13 flow-control settings (0x2b61/0x2b64/0x2b65):
  Apple REJECTS sessions when they are present.
- Parse the ratified ids from peer SETTINGS into enable_webtransport /
  max_webtransport_sessions.
- accept(): drop the hard requirement that the CLIENT advertise WT/datagram
  settings — ratified clients send none; the extended CONNECT is the
  declaration. (Was a connection-fatal H3_SETTINGS_ERROR for Safari.)
- Document that max_webtransport_sessions MUST stay 1 while this stack is
  single-session: advertising >1 flips Apple NF into a multi-session mode it
  then half-opens (ready resolves but stream creation returns null ids).
- SETTINGS_LEN 8 -> 16 for the added ids (tests updated).
2026-07-05 15:15:46 +01:00
.github ci(fuzz): drop --locked from cargo-fuzz install (#1468) 2026-05-10 15:08:32 +08:00
assets Remove Whore are using section 2026-01-28 08:25:47 +08:00
crates WebTransport interop with ratified-era clients (Safari/WebKit NF) 2026-07-05 15:15:46 +01:00
examples Code quality: cleaned up some RustRover warnings (#1544) 2026-06-19 13:34:19 +08:00
fuzz Fix naming and documentation inconsistencies (#1497) 2026-05-24 10:55:46 +08:00
vendor WebTransport interop with ratified-era clients (Safari/WebKit NF) 2026-07-05 15:15:46 +01:00
.gitignore chore: update .gitignore to include _*.md and retain .claude 2026-04-01 07:33:53 +08:00
Cargo.toml Merge upstream salvo through de07397a 2026-05-15 19:41:37 +01:00
CHANGELOG.md Add changelog skeleton (#1403) 2026-04-16 20:39:43 +08:00
CONTRIBUTING.md Clean up P3 naming and docs (#1545) 2026-06-20 07:41:15 +08:00
ECOSYSTEM.md fix: reorder project showcase entries in ECOSYSTEM.md 2026-03-18 07:37:13 +08:00
LICENSE Update license to Apache-2.0 and remove MIT license files 2026-04-02 08:34:40 +08:00
README.md expand README and rustdoc examples (#1500) 2026-05-24 15:01:21 +08:00
README.zh-hant.md expand README and rustdoc examples (#1500) 2026-05-24 15:01:21 +08:00
README.zh.md expand README and rustdoc examples (#1500) 2026-05-24 15:01:21 +08:00
rustfmt.toml fix: update multer references to multra for compatibility (#1377) 2026-04-02 07:03:36 +08:00
SECURITY.md Expand security policy (#1402) 2026-04-16 20:39:20 +08:00
typos.toml refactor: performance optimizations (#1316) 2026-02-03 08:01:16 +08:00

Salvo

A powerful and simple Rust web framework

English   简体中文   繁體中文

build status build status build status codecov
crates.io Documentation Download unsafe forbidden Rust Version
Website

Features

  • Simple & Powerful - Minimal boilerplate. If you can write a function, you can write a handler.
  • HTTP/1, HTTP/2 & HTTP/3 - Full protocol support out of the box.
  • Flexible Routing - Tree-based routing with middleware support at any level.
  • Auto TLS - ACME integration for automatic certificate management.
  • OpenAPI - First-class OpenAPI support with auto-generated documentation.
  • WebSocket & WebTransport - Real-time communication built-in.
  • Built on Hyper & Tokio - Production-ready async foundation.

Quick Start

Create a new project:

cargo new hello-salvo
cd hello-salvo
cargo add salvo tokio --features salvo/oapi,tokio/macros

Write your first app in src/main.rs:

use salvo::prelude::*;

#[handler]
async fn hello() -> &'static str {
    "Hello World"
}

#[tokio::main]
async fn main() {
    let router = Router::new().get(hello);
    let acceptor = TcpListener::new("127.0.0.1:7878").bind().await;
    Server::new(acceptor).serve(router).await;
}

Run it:

cargo run

Why Salvo?

Middleware = Handler

No complex traits or generics. Middleware is just a handler:

#[handler]
async fn add_header(res: &mut Response) {
    res.headers_mut().insert(header::SERVER, HeaderValue::from_static("Salvo"));
}

Router::new().hoop(add_header).get(hello)

Tree Routing with Middleware

Apply middleware to specific route branches:

Router::new()
    // Public routes
    .push(Router::with_path("articles").get(list_articles))
    // Protected routes
    .push(Router::with_path("articles").hoop(auth_check).post(create_article).delete(delete_article))

JSON APIs

Salvo handlers can deserialize request bodies and return typed JSON responses:

use salvo::http::ParseError;
use salvo::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Deserialize)]
struct CreateTodo {
    text: String,
}

#[derive(Serialize)]
struct Todo {
    id: u64,
    text: String,
}

#[handler]
async fn create_todo(req: &mut Request) -> Result<Json<Todo>, ParseError> {
    let payload = req.parse_json::<CreateTodo>().await?;
    Ok(Json(Todo {
        id: 1,
        text: payload.text,
    }))
}

For this pattern, add Serde's derive feature:

cargo add serde --features derive

OpenAPI in One Line

Just change #[handler] to #[endpoint]:

#[endpoint]
async fn hello() -> &'static str {
    "Hello World"
}

Auto HTTPS with ACME

Get TLS certificates automatically from Let's Encrypt:

let listener = TcpListener::new("0.0.0.0:443")
    .acme()
    .add_domain("example.com")
    .http01_challenge(&mut router)
    .quinn("0.0.0.0:443"); // HTTP/3 support

CLI Tool

cargo install salvo-cli
salvo new my_project

Learn More

  • Savhub - Easily manage your AI skills. A platform built with Salvo for organizing and sharing AI capabilities.
  • Palpo - A Matrix server implementation in Rust, powered by Salvo.

Check out the full list of community projects in our ECOSYSTEM.md.

Performance

Salvo consistently ranks among the fastest Rust web frameworks:

Support

If you find Salvo useful, consider buying me a coffee.

License

Licensed under Apache License 2.0.