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§
Sourcefn filter(
&self,
client_addr: SocketAddr,
server_addr: SocketAddr,
error_response: &mut Response,
) -> Result<(), Handled>
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§
Sourcefn filter_async(
&self,
client_addr: SocketAddr,
server_addr: SocketAddr,
error_response: &mut Response,
) -> impl Future<Output = Result<(), Handled>> + Send
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.