HTTP/3 Support

Salvo provides support for HTTP/3, which can be enabled via the quinn feature. HTTP/3 is based on the QUIC protocol and offers lower latency and better performance compared to traditional HTTP/1.1 and HTTP/2, especially in unstable network environments.

Enabling HTTP/3 Support

To enable HTTP/3 support in Salvo, you need to activate the quinn feature in your Cargo.toml file:

salvo = { workspace = true, features = ["quinn"] }

HTTP/3 Use Cases

HTTP/3 is particularly suitable for the following scenarios:

  • Applications on mobile devices and in unstable network environments
  • Real-time applications requiring low latency
  • Scenarios involving parallel downloads of numerous small files
  • Applications needing connection migration (e.g., seamless switching from WiFi to cellular networks without connection interruption)

Example Code

The following is a simple HTTP/3 server example that supports both HTTP/3 (QUIC) and HTTPS (TCP):

use salvo::conn::rustls::{Keycert, RustlsConfig};
use salvo::prelude::*;

// Handler function that responds with "Hello World"
#[handler]
async fn hello() -> &'static str {
    "Hello World"
}

#[tokio::main]
async fn main() {
    // Initialize the logging system
    tracing_subscriber::fmt().init();

    // Load TLS certificate and private key from embedded PEM files
    let cert = include_bytes!("../certs/cert.pem").to_vec();
    let key = include_bytes!("../certs/key.pem").to_vec();

    // Create a router and add an endpoint
    let router = Router::new().get(hello);

    // Configure TLS settings using Rustls
    let config = RustlsConfig::new(Keycert::new().cert(cert.as_slice()).key(key.as_slice()));

    // Create a TLS-encrypted TCP listener on port 5800
    let listener = TcpListener::new(("0.0.0.0", 5800)).rustls(config.clone());

    // Create a QUIC listener and combine it with the TCP listener
    let acceptor = QuinnListener::new(config.build_quinn_config().unwrap(), ("0.0.0.0", 5800))
        .join(listener)
        .bind()
        .await;

    // Start the server supporting both HTTP/3 (QUIC) and HTTPS (TCP)
    Server::new(acceptor).serve(router).await;
}

Key Code Analysis

TLS Configuration

// Configure TLS settings using Rustls
let config = RustlsConfig::new(Keycert::new().cert(cert.as_slice()).key(key.as_slice()));

Since HTTP/3 is based on the QUIC protocol, which requires TLS 1.3 for encryption, TLS certificates and keys must be configured. In Salvo, we use RustlsConfig to configure TLS.

Combining Listeners

// Create a TLS-encrypted TCP listener
let listener = TcpListener::new(("0.0.0.0", 5800)).rustls(config.clone());

// Create a QUIC listener and combine it with the TCP listener
let acceptor = QuinnListener::new(config.build_quinn_config().unwrap(), ("0.0.0.0", 5800))
    .join(listener)
    .bind()
    .await;

This code is the core part of handling HTTP/3 in Salvo. It first creates a TLS-enabled TCP listener (for HTTP/1.1 and HTTP/2), then creates a QUIC listener (for HTTP/3). The join method combines these two listeners, enabling the server to handle requests from different protocols simultaneously.

Running the Example

To run this example, you need valid TLS certificates and private keys. In a development environment, self-signed certificates can be used. The complete example code can be found in the Salvo GitHub repository.

Note that since many clients do not yet fully support HTTP/3, it is essential for this server to support both HTTP/3 and HTTPS.

Considerations

  1. HTTP/3 requires TLS 1.3 support, so valid certificates and keys must be configured.
  2. Clients must support the HTTP/3 protocol to utilize this feature; otherwise, they will fall back to HTTP/1.1 or HTTP/2.
  3. In production environments, certificates issued by a trusted Certificate Authority (CA) should be used instead of self-signed certificates.