ConnectionFilter

Trait ConnectionFilter 

Source
pub trait ConnectionFilter:
    Sync
    + Send
    + 'static {
    // Required method
    fn filter(
        &self,
        client_addr: SocketAddr,
        server_addr: SocketAddr,
        error_response: &mut Response,
    ) -> Result<(), Handled>;

    // Provided method
    fn filter_async(
        &self,
        client_addr: SocketAddr,
        server_addr: SocketAddr,
        error_response: &mut Response,
    ) -> impl Future<Output = Result<(), Handled>> + Send { ... }
}
Expand description

A trait for filtering TCP connections before HTTP processing.

§Examples

Simple IP Blacklist:

use std::{collections::HashSet, net::{SocketAddr, IpAddr}};
use maker_web::{Server, ConnectionFilter, Response, Handled, StatusCode};

struct MyConnFilter {
    blacklist: HashSet<IpAddr>
}

impl ConnectionFilter for MyConnFilter {
    fn filter(
        &self, client_addr: SocketAddr, _: SocketAddr, err_resp: &mut Response
    ) -> Result<(), Handled> {
        if self.blacklist.contains(&client_addr.ip()) {
            Err(err_resp
                .status(StatusCode::Forbidden)
                .body("Your IP is permanently banned"))
        } else {
            Ok(())
        }
    }
}

File-based IP blacklist:

use std::net::SocketAddr;
use maker_web::{Server, ConnectionFilter, Response, Handled, StatusCode};

struct MyConnFilter {
    db: DatabaseClient
}

impl ConnectionFilter for MyConnFilter {
    fn filter(&self, _: SocketAddr, _: SocketAddr, _: &mut Response) -> Result<(), Handled> {
        Ok(())
    }

    async fn filter_async(
        &self,
        client_addr: SocketAddr,
        _: SocketAddr,
        err_resp: &mut Response,
    ) -> Result<(), Handled> {
        let request = format!(
            "SELECT EXISTS (SELECT 1 FROM ip_blacklist WHERE ip_address = '{}')",
            client_addr.ip()
        );

        if self.db.execute(&request).await == Some(vec!["false"]) {
            Ok(()) // IP not found in blacklist
        } else {
            Err(err_resp
                .status(StatusCode::Forbidden)
                .body("IP found in blacklist file"))
        }
    }
}

Two-stage filtering with cache:

use std::{collections::HashSet, sync::RwLock, net::{SocketAddr, IpAddr}};
use maker_web::{Server, ConnectionFilter, Response, Handled, StatusCode};

struct MyConnFilter {
    cache: RwLock<HashSet<IpAddr>>,
    db: DatabaseClient,
}

impl ConnectionFilter for MyConnFilter {
    fn filter(
        &self, client_addr: SocketAddr, _: SocketAddr, err_resp: &mut Response
    ) -> Result<(), Handled> {
        let Ok(guard) = self.cache.read() else {
            return Err(err_resp.status(StatusCode::InternalServerError)
                .body("Internal server error"));
        };

        if guard.contains(&client_addr.ip()) {
            Err(err_resp
                .status(StatusCode::Forbidden)
                .body("Your IP is permanently banned"))
        } else {
            Ok(())
        }
    }

    async fn filter_async(
        &self,
        client_addr: SocketAddr,
        _: SocketAddr,
        err_resp: &mut Response,
    ) -> Result<(), Handled> {
        let request = format!(
            "SELECT EXISTS (SELECT 1 FROM ip_blacklist WHERE ip_address = '{}')",
            client_addr.ip()
        );

        if self.db.execute(&request).await == Some(vec!["false"]) {
            Ok(()) // IP not found in blacklist
        } else {
            let Ok(mut guard) = self.cache.write() else {
                return Err(err_resp.status(StatusCode::InternalServerError)
                    .body("Internal server error"));
            };
            guard.insert(client_addr.ip());

            Err(err_resp
                .status(StatusCode::Forbidden)
                .body("IP found in blacklist file"))
        }
    }
}

§Connection Filter Architecture

                    [ QUEUE TCP_STREAM ]
                             ||
/----------------------------||----------------------------------\
|                            || TCP_STREAM            Tokio Task |
|       /=====================/                                  |
|       \/                                                       |
|   [--------]   Err(Handled)   [----------------------]         |
|   [ filter ] ===============> [ Send `error_response`]         |
|   [--------]                  [----------------------]         |
|       ||                                 /\                    |
|       || Ok(())                          ||                    |
|       \/                Err(Handled)     ||                    |
|   [--------------] ========================/                   |
|   [ filter_async ]                             [-----------]   |
|   [--------------] ==========================> [  Handler  ]   |
|                             Ok(())             [-----------]   |
|                                                                |
\----------------------------------------------------------------/

Required Methods§

Source

fn filter( &self, client_addr: SocketAddr, server_addr: SocketAddr, error_response: &mut Response, ) -> Result<(), Handled>

Synchronous connection validation.

Perform fast, in-memory checks here. Expensive operations should be deferred to filter_async.

Use for:

  • IP blacklist/whitelist (in-memory cache)
  • Geographic IP restrictions
  • Rate limiting counters

Provided Methods§

Source

fn filter_async( &self, client_addr: SocketAddr, server_addr: SocketAddr, error_response: &mut Response, ) -> impl Future<Output = Result<(), Handled>> + Send

Asynchronous connection inspection.

Called after filter succeeds.Executes asynchronously within the Tokio runtime.

Use for:

  • Database lookups
  • External API calls
  • File system operations
  • Complex business logic
  • Machine learning inference

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementations on Foreign Types§

Source§

impl ConnectionFilter for ()

Source§

fn filter( &self, _: SocketAddr, _: SocketAddr, _: &mut Response, ) -> Result<(), Handled>

Implementors§