9 releases (breaking)

new 0.8.0 Oct 14, 2024
0.6.1 Mar 14, 2024
0.3.0 Oct 2, 2023

#520 in Text processing

Download history 3/week @ 2024-07-06 61/week @ 2024-07-27 127/week @ 2024-09-07 27/week @ 2024-09-14 19/week @ 2024-09-21 17/week @ 2024-09-28 2/week @ 2024-10-05 160/week @ 2024-10-12

200 downloads per month

MIT license

25KB
470 lines

TOWER ALLOWED HOSTS

Project status & info:

License Crates Version Docs
License: MIT Crate Docs

Tower service which limits request from only specified hosts All hostnames are automatically converted to lowercase before matching.

Add as dependencies

In your Cargo.toml file, add tower_allowed_hosts as a dependency:

[dependencies]
tower_allowed_hosts = "0.8.0"

Usage

Basic

To restrict access to specific basic hosts, you can use the following code:

let tower_layer = tower_allowed_hosts::AllowedHostLayer::default()
    .extend_hosts(&["127.0.0.1".to_string()]);

Wildcard

If you need wildcard-based host matching, enable the wildcard feature in your Cargo.toml:

[dependencies]
tower_allowed_hosts = { version = "0.8.0", features = ["wildcard"] }

You can then restrict hosts using wildcards:

let tower_layer = tower_allowed_hosts::AllowedHostLayer::default()
    .extend_hosts(&[wildmatch::WildMatch::new("127.0.0.*")]);

Regex

If you need regex-based host matching, enable the regex feature in your Cargo.toml:

[dependencies]
tower_allowed_hosts = { version = "0.8.0", features = ["regex"] }

You can then restrict hosts using regex patterns:

let tower_layer = tower_allowed_hosts::AllowedHostLayer::new(&[regex::Regex::new("^127.0.0.1$")?]);

Integrating with a Tower-Compatible Library

After creating the AllowedHostLayer, it can be integrated into any library that supports tower components. Here's an example of how to use this layer in an axum application. You will also need to handle errors properly using HandleErrorLayer:

use axum::{
    error_handling::HandleErrorLayer,
    http::StatusCode,
    Router
};
use tower::ServiceBuilder;
use tower_allowed_hosts::AllowedHostLayer;

fn router() -> Router {
    let handle_error_layer = HandleErrorLayer::new(handle_box_error);

    let allowed_hosts_layer = AllowedHostLayer::default()
        .extend_hosts(&[wildmatch::WildMatch::new("127.0.0.*")]);

     let layer = ServiceBuilder::new()
        .layer(handle_error_layer)
        .layer(allowed_hosts_layer);

    Router::new().layer(layer)
}

async fn handle_box_error(err: tower::BoxError) -> (StatusCode, String) {
    if err.is::<tower_allowed_hosts::error::Error>() {
        return (StatusCode::BAD_REQUEST, err.to_string());
    }
    return (StatusCode::INTERNAL_SERVER_ERROR, "".to_string())
}

There is also extension added after successfully parsing allowed host and allowing host which can be access using tower_allowed_hosts::Host struct Extension

Dependencies

~1.2–2.4MB
~42K SLoC