Skip to content

Commit

Permalink
Make Filter::filter async (#933)
Browse files Browse the repository at this point in the history
* Make Filter:filter async

* test

* cargo clippy
  • Loading branch information
chrislearn committed Sep 27, 2024
1 parent 7b2377b commit 9b5d826
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 123 deletions.
119 changes: 85 additions & 34 deletions crates/core/src/routing/filters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ mod path;
use std::fmt::{self, Debug, Formatter};

use self::opts::*;
use crate::async_trait;
use crate::http::uri::Scheme;
use crate::http::{Method, Request};
use crate::routing::PathState;
Expand All @@ -21,6 +22,7 @@ pub use path::*;
///
/// View [module level documentation](../index.html) for more details.

#[async_trait]
pub trait Filter: Debug + Send + Sync + 'static {
#[doc(hidden)]
fn type_id(&self) -> std::any::TypeId {
Expand Down Expand Up @@ -83,20 +85,21 @@ pub trait Filter: Debug + Send + Sync + 'static {
}

/// Filter `Request` and returns false or true.
fn filter(&self, req: &mut Request, path: &mut PathState) -> bool;
async fn filter(&self, req: &mut Request, path: &mut PathState) -> bool;
}

/// `FnFilter` accepts a function as it's param, use this function to filter request.
#[derive(Copy, Clone)]
#[allow(missing_debug_implementations)]
pub struct FnFilter<F>(pub F);

#[async_trait]
impl<F> Filter for FnFilter<F>
where
F: Fn(&mut Request, &mut PathState) -> bool + Send + Sync + 'static,
{
#[inline]
fn filter(&self, req: &mut Request, path: &mut PathState) -> bool {
async fn filter(&self, req: &mut Request, path: &mut PathState) -> bool {
self.0(req, path)
}
}
Expand Down Expand Up @@ -183,8 +186,8 @@ mod tests {
assert!(delete() == MethodFilter(Method::DELETE));
}

#[test]
fn test_opts() {
#[tokio::test]
async fn test_opts() {
fn has_one(_req: &mut Request, path: &mut PathState) -> bool {
path.parts.contains(&"one".into())
}
Expand All @@ -197,39 +200,87 @@ mod tests {

let mut req = Request::default();
let mut path_state = PathState::new("http://localhost/one");
assert!(one_filter.filter(&mut req, &mut path_state));
assert!(!two_filter.filter(&mut req, &mut path_state));
assert!(one_filter
.or_else(has_two)
.filter(&mut req, &mut path_state));
assert!(one_filter.or(two_filter).filter(&mut req, &mut path_state));
assert!(!one_filter
.and_then(has_two)
.filter(&mut req, &mut path_state));
assert!(!one_filter.and(two_filter).filter(&mut req, &mut path_state));
assert!(one_filter.filter(&mut req, &mut path_state).await);
assert!(!two_filter.filter(&mut req, &mut path_state).await);
assert!(
one_filter
.or_else(has_two)
.filter(&mut req, &mut path_state)
.await
);
assert!(
one_filter
.or(two_filter)
.filter(&mut req, &mut path_state)
.await
);
assert!(
!one_filter
.and_then(has_two)
.filter(&mut req, &mut path_state)
.await
);
assert!(
!one_filter
.and(two_filter)
.filter(&mut req, &mut path_state)
.await
);

let mut path_state = PathState::new("http://localhost/one/two");
assert!(one_filter.filter(&mut req, &mut path_state));
assert!(two_filter.filter(&mut req, &mut path_state));
assert!(one_filter
.or_else(has_two)
.filter(&mut req, &mut path_state));
assert!(one_filter.or(two_filter).filter(&mut req, &mut path_state));
assert!(one_filter
.and_then(has_two)
.filter(&mut req, &mut path_state));
assert!(one_filter.and(two_filter).filter(&mut req, &mut path_state));
assert!(one_filter.filter(&mut req, &mut path_state).await);
assert!(two_filter.filter(&mut req, &mut path_state).await);
assert!(
one_filter
.or_else(has_two)
.filter(&mut req, &mut path_state)
.await
);
assert!(
one_filter
.or(two_filter)
.filter(&mut req, &mut path_state)
.await
);
assert!(
one_filter
.and_then(has_two)
.filter(&mut req, &mut path_state)
.await
);
assert!(
one_filter
.and(two_filter)
.filter(&mut req, &mut path_state)
.await
);

let mut path_state = PathState::new("http://localhost/two");
assert!(!one_filter.filter(&mut req, &mut path_state));
assert!(two_filter.filter(&mut req, &mut path_state));
assert!(one_filter
.or_else(has_two)
.filter(&mut req, &mut path_state));
assert!(one_filter.or(two_filter).filter(&mut req, &mut path_state));
assert!(!one_filter
.and_then(has_two)
.filter(&mut req, &mut path_state));
assert!(!one_filter.and(two_filter).filter(&mut req, &mut path_state));
assert!(!one_filter.filter(&mut req, &mut path_state).await);
assert!(two_filter.filter(&mut req, &mut path_state).await);
assert!(
one_filter
.or_else(has_two)
.filter(&mut req, &mut path_state)
.await
);
assert!(
one_filter
.or(two_filter)
.filter(&mut req, &mut path_state)
.await
);
assert!(
!one_filter
.and_then(has_two)
.filter(&mut req, &mut path_state)
.await
);
assert!(
!one_filter
.and(two_filter)
.filter(&mut req, &mut path_state)
.await
);
}
}
26 changes: 15 additions & 11 deletions crates/core/src/routing/filters/opts.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::fmt::{self, Formatter};

use crate::async_trait;
use crate::http::Request;
use crate::routing::{Filter, PathState};

Expand All @@ -9,17 +10,18 @@ pub struct Or<T, U> {
pub(super) second: U,
}

#[async_trait]
impl<T, U> Filter for Or<T, U>
where
T: Filter + Send,
U: Filter + Send,
{
#[inline]
fn filter(&self, req: &mut Request, state: &mut PathState) -> bool {
if self.first.filter(req, state) {
async fn filter(&self, req: &mut Request, state: &mut PathState) -> bool {
if self.first.filter(req, state).await {
true
} else {
self.second.filter(req, state)
self.second.filter(req, state).await
}
}
}
Expand All @@ -29,15 +31,15 @@ pub struct OrElse<T, F> {
pub(super) filter: T,
pub(super) callback: F,
}

#[async_trait]
impl<T, F> Filter for OrElse<T, F>
where
T: Filter,
F: Fn(&mut Request, &mut PathState) -> bool + Send + Sync + 'static,
{
#[inline]
fn filter(&self, req: &mut Request, state: &mut PathState) -> bool {
if self.filter.filter(req, state) {
async fn filter(&self, req: &mut Request, state: &mut PathState) -> bool {
if self.filter.filter(req, state).await {
true
} else {
(self.callback)(req, state)
Expand All @@ -57,17 +59,18 @@ pub struct And<T, U> {
pub(super) second: U,
}

#[async_trait]
impl<T, U> Filter for And<T, U>
where
T: Filter,
U: Filter,
{
#[inline]
fn filter(&self, req: &mut Request, state: &mut PathState) -> bool {
if !self.first.filter(req, state) {
async fn filter(&self, req: &mut Request, state: &mut PathState) -> bool {
if !self.first.filter(req, state).await {
false
} else {
self.second.filter(req, state)
self.second.filter(req, state).await
}
}
}
Expand All @@ -78,14 +81,15 @@ pub struct AndThen<T, F> {
pub(super) callback: F,
}

#[async_trait]
impl<T, F> Filter for AndThen<T, F>
where
T: Filter,
F: Fn(&mut Request, &mut PathState) -> bool + Send + Sync + 'static,
{
#[inline]
fn filter(&self, req: &mut Request, state: &mut PathState) -> bool {
if !self.filter.filter(req, state) {
async fn filter(&self, req: &mut Request, state: &mut PathState) -> bool {
if !self.filter.filter(req, state).await {
false
} else {
(self.callback)(req, state)
Expand Down
17 changes: 13 additions & 4 deletions crates/core/src/routing/filters/others.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::fmt::{self, Debug, Formatter};

use crate::async_trait;
use crate::http::uri::Scheme;
use crate::http::{Method, Request};
use crate::routing::{Filter, PathState};
Expand All @@ -13,9 +14,11 @@ impl MethodFilter {
Self(method)
}
}

#[async_trait]
impl Filter for MethodFilter {
#[inline]
fn filter(&self, req: &mut Request, _state: &mut PathState) -> bool {
async fn filter(&self, req: &mut Request, _state: &mut PathState) -> bool {
req.method() == self.0
}
}
Expand Down Expand Up @@ -49,9 +52,11 @@ impl SchemeFilter {
self
}
}

#[async_trait]
impl Filter for SchemeFilter {
#[inline]
fn filter(&self, req: &mut Request, _state: &mut PathState) -> bool {
async fn filter(&self, req: &mut Request, _state: &mut PathState) -> bool {
req.uri()
.scheme()
.map(|s| s == &self.scheme)
Expand Down Expand Up @@ -87,9 +92,11 @@ impl HostFilter {
self
}
}

#[async_trait]
impl Filter for HostFilter {
#[inline]
fn filter(&self, req: &mut Request, _state: &mut PathState) -> bool {
async fn filter(&self, req: &mut Request, _state: &mut PathState) -> bool {
// Http1, if `fix-http1-request-uri` feature is disabled, host is lack. so use header host instead.
// https://github.com/hyperium/hyper/issues/1310
#[cfg(feature = "fix-http1-request-uri")]
Expand Down Expand Up @@ -141,9 +148,11 @@ impl PortFilter {
self
}
}

#[async_trait]
impl Filter for PortFilter {
#[inline]
fn filter(&self, req: &mut Request, _state: &mut PathState) -> bool {
async fn filter(&self, req: &mut Request, _state: &mut PathState) -> bool {
// Http1, if `fix-http1-request-uri` feature is disabled, port is lack. so use header host instead.
// https://github.com/hyperium/hyper/issues/1310
#[cfg(feature = "fix-http1-request-uri")]
Expand Down
4 changes: 3 additions & 1 deletion crates/core/src/routing/filters/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use indexmap::IndexSet;
use parking_lot::RwLock;
use regex::Regex;

use crate::async_trait;
use crate::http::Request;
use crate::routing::{Filter, PathState};

Expand Down Expand Up @@ -959,9 +960,10 @@ impl Debug for PathFilter {
write!(f, "path:{}", &self.raw_value)
}
}
#[async_trait]
impl Filter for PathFilter {
#[inline]
fn filter(&self, _req: &mut Request, state: &mut PathState) -> bool {
async fn filter(&self, _req: &mut Request, state: &mut PathState) -> bool {
self.detect(state)
}
}
Expand Down
Loading

0 comments on commit 9b5d826

Please sign in to comment.