Skip to the content.

XWS

Crates.io downloads crates.io Build Status Crates.io MSRV Documentation MIT licensed codecov

XWS is a lightweight yet powerful web server that brings simplicity and performance together. Designed with Rust’s safety guarantees in mind, it delivers HTTP/1, HTTP/2, and HTTP/3 support with a clean, intuitive API that makes building web services a breeze.

Built on top of hyper.

History

XWS started as a component of deboa-tests, a private crate used by deboa http client for integration testing purposes, as it got more features, like HTTP1/2 and 3 support, alongside TLS, I realized project could be reused somehow.

So with reusability in mind, I started EasyHttpMock, a project which aims to be a quick and easy way to start a mock server for integration purposes, it didn’t took too much to realized this internal http server used by EasyHttpMock could be reused for other purposes than simply be a mock server.

That’s why XWS came to reality, by taking advantage of what I started on deboa-tests for testing purposes, it turned into a complete http server project, the goal is make it very flexible, while keeping it small and fast.

Features

Quick Start

Add XWS to your Cargo.toml:

[dependencies]
xws = { version = "0.1.4-beta.2", features = ["tokio-rt", "http2", "tokio-rust-tls"] }

Basic usage:

use hyper::StatusCode;

#[cfg(feature = "smol")]
use macro_rules_attribute::apply;
#[cfg(feature = "smol")]
use smol_macros::main;

use xws::{
    config::server::{
        virtual_host::{
            path::proxy::ProxyPathConfig, path::static_files::StaticPathConfig, SecurityConfig,
            VirtualHostConfig,
        },
        ListenerConfig, Protocol, ServerConfig,
    },
    server::virtual_host::{
        handler_fn,
        path::{proxy::ProxyPath, static_files::StaticPath, HandlerPath},
        VirtualHost,
    },
    Vetis,
};

pub(crate) const CA_CERT: &[u8] = include_bytes!("../certs/ca.der");

pub(crate) const SERVER_CERT: &[u8] = include_bytes!("../certs/server.der");
pub(crate) const SERVER_KEY: &[u8] = include_bytes!("../certs/server.key.der");

#[cfg(feature = "tokio")]
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    run().await
}

#[cfg(feature = "smol")]
#[apply(main!)]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    run().await
}

async fn run() -> Result<(), Box<dyn std::error::Error>> {
    env_logger::Builder::from_env(env_logger::Env::default().filter_or("RUST_LOG", "error")).init();

    let https = ListenerConfig::builder()
        .port(8443)
        .protocol(Protocol::Http1)
        .interface("0.0.0.0")
        .build()?;

    let config = ServerConfig::builder()
        .add_listener(https)
        .build()?;

    let security_config = SecurityConfig::builder()
        .ca_cert_from_bytes(CA_CERT.to_vec())
        .cert_from_bytes(SERVER_CERT.to_vec())
        .key_from_bytes(SERVER_KEY.to_vec())
        .build()?;

    let localhost_config = VirtualHostConfig::builder()
        .hostname("localhost")
        .port(8443)
        .security(security_config)
        .root_directory("/home/rogerio/Downloads")
        .status_pages(maplit::hashmap! {
            404 => "404.html".to_string(),
            500 => "500.html".to_string(),
        })
        .build()?;

    let mut localhost_virtual_host = VirtualHost::new(localhost_config);

    let root_path = HandlerPath::builder()
        .uri("/hello")
        .handler(handler_fn(|request| async move {
            let response = xws::Response::builder()
                .status(StatusCode::OK)
                .text("Hello from localhost");
            Ok(response)
        }))
        .build()?;

    localhost_virtual_host.add_path(root_path);

    let health_path = HandlerPath::builder()
        .uri("/health")
        .handler(handler_fn(|request| async move {
            let response = xws::Response::builder()
                .status(StatusCode::OK)
                .text("Health check");
            Ok(response)
        }))
        .build()?;

    localhost_virtual_host.add_path(health_path);

    let proxy_path = ProxyPathConfig::builder()
        .uri("/proxy")
        .target("http://localhost:5230")
        .build()?;

    localhost_virtual_host.add_path(ProxyPath::new(proxy_path));

    let images_path = StaticPathConfig::builder()
        .uri("/images")
        .directory("/home/rogerio/Downloads")
        .extensions("\\.(jpg|png|gif|html)$")
        .index_files(vec!["index.html".to_string()])
        .build()?;

    localhost_virtual_host.add_path(StaticPath::new(images_path));

    let mut server = Vetis::new(config);
    server
        .add_virtual_host(localhost_virtual_host)
        .await;

    server.run().await?;

    server
        .stop()
        .await?;

    Ok(())
}

Crates

Crate Description Documentation
xws Core HTTP server library docs.rs
xws-macros Macros for Vetis docs.rs

Standalone Server

Check out the standalone server for complete examples of how to use Vetis as a standalone server.

Examples

Check out the examples for complete examples of how to use Vetis in your projects.

Create project from template

You can create a new project from the template using cargo generate:

cargo generate ararog/xws-templates

Benchmarks

Check out the benchmarks for performance details.

Documentation

Other Projects

License

This project is licensed under the MIT License.

Author

Rogerio Pereira Araujo rogerio.araujo@gmail.com