use async_trait::async_trait;
use bytes::Bytes;
pub(crate) use crate::context::HttpFilterContext;
use crate::{
actions::FilterAction,
body::{BodyAccess, BodyMode},
builtins::http::payload_processing::compression_config::CompressionConfig,
};
pub type Filter = dyn HttpFilter;
pub type FilterContext<'a> = HttpFilterContext<'a>;
#[async_trait]
pub trait HttpFilter: Send + Sync {
fn name(&self) -> &'static str;
async fn on_request(&self, ctx: &mut HttpFilterContext<'_>) -> Result<FilterAction, FilterError>;
async fn on_response(&self, ctx: &mut HttpFilterContext<'_>) -> Result<FilterAction, FilterError> {
let _ = ctx;
Ok(FilterAction::Continue)
}
fn request_body_access(&self) -> BodyAccess {
BodyAccess::None
}
fn response_body_access(&self) -> BodyAccess {
BodyAccess::None
}
fn request_body_mode(&self) -> BodyMode {
BodyMode::Stream
}
fn response_body_mode(&self) -> BodyMode {
BodyMode::Stream
}
fn needs_request_context(&self) -> bool {
false
}
fn compression_config(&self) -> Option<&CompressionConfig> {
None
}
async fn on_request_body(
&self,
ctx: &mut HttpFilterContext<'_>,
body: &mut Option<Bytes>,
end_of_stream: bool,
) -> Result<FilterAction, FilterError> {
let _ = (ctx, body, end_of_stream);
Ok(FilterAction::Continue)
}
fn on_response_body(
&self,
ctx: &mut HttpFilterContext<'_>,
body: &mut Option<Bytes>,
end_of_stream: bool,
) -> Result<FilterAction, FilterError> {
let _ = (ctx, body, end_of_stream);
Ok(FilterAction::Continue)
}
}
pub type FilterError = Box<dyn std::error::Error + Send + Sync>;
#[cfg(test)]
mod tests {
use async_trait::async_trait;
use super::*;
use crate::{FilterAction, FilterError};
#[tokio::test]
async fn default_on_response_returns_continue() {
let filter = MinimalFilter;
let req = crate::test_utils::make_request(http::Method::GET, "/");
let mut ctx = crate::test_utils::make_filter_context(&req);
let action = filter.on_response(&mut ctx).await.unwrap();
assert!(
matches!(action, FilterAction::Continue),
"default on_response should return Continue"
);
}
#[test]
fn default_body_access_is_none() {
let filter = MinimalFilter;
assert_eq!(
filter.request_body_access(),
BodyAccess::None,
"default request body access should be None"
);
assert_eq!(
filter.response_body_access(),
BodyAccess::None,
"default response body access should be None"
);
assert_eq!(
filter.request_body_mode(),
BodyMode::Stream,
"default request body mode should be Stream"
);
assert_eq!(
filter.response_body_mode(),
BodyMode::Stream,
"default response body mode should be Stream"
);
assert!(
!filter.needs_request_context(),
"default needs_request_context should be false"
);
}
struct MinimalFilter;
#[async_trait]
impl HttpFilter for MinimalFilter {
fn name(&self) -> &'static str {
"minimal"
}
async fn on_request(&self, _ctx: &mut HttpFilterContext<'_>) -> Result<FilterAction, FilterError> {
Ok(FilterAction::Continue)
}
}
}