Skip to main content

praxis_filter/
any_filter.rs

1// SPDX-License-Identifier: MIT
2// Copyright (c) 2024 Praxis Contributors
3
4//! Protocol-tagged filter wrapper for storage in a mixed-protocol pipeline.
5
6use praxis_core::config::ProtocolKind;
7
8use crate::{filter::HttpFilter, tcp_filter::TcpFilter};
9
10// -----------------------------------------------------------------------------
11// AnyFilter
12// -----------------------------------------------------------------------------
13
14/// A filter of any protocol level, for storage in a pipeline.
15///
16/// Wraps either an [`HttpFilter`] or a [`TcpFilter`], preserving its
17/// protocol level for compatibility checks during pipeline construction.
18///
19/// [`HttpFilter`]: crate::HttpFilter
20/// [`TcpFilter`]: crate::TcpFilter
21pub enum AnyFilter {
22    /// An HTTP-level filter.
23    Http(Box<dyn HttpFilter>),
24
25    /// A TCP-level filter.
26    Tcp(Box<dyn TcpFilter>),
27}
28
29impl AnyFilter {
30    /// The filter's name.
31    pub fn name(&self) -> &'static str {
32        match self {
33            Self::Http(f) => f.name(),
34            Self::Tcp(f) => f.name(),
35        }
36    }
37
38    /// The protocol level this filter operates at.
39    pub fn protocol_level(&self) -> ProtocolKind {
40        match self {
41            Self::Http(_) => ProtocolKind::Http,
42            Self::Tcp(_) => ProtocolKind::Tcp,
43        }
44    }
45}
46
47// -----------------------------------------------------------------------------
48// Tests
49// -----------------------------------------------------------------------------
50
51#[cfg(test)]
52mod tests {
53    use async_trait::async_trait;
54
55    use super::*;
56    use crate::{
57        actions::FilterAction,
58        filter::{FilterError, HttpFilterContext},
59    };
60
61    #[test]
62    fn http_variant_protocol_level() {
63        let f = AnyFilter::Http(Box::new(StubHttpFilter));
64        assert_eq!(
65            f.protocol_level(),
66            ProtocolKind::Http,
67            "Http variant should report Http protocol"
68        );
69    }
70
71    #[test]
72    fn tcp_variant_protocol_level() {
73        let f = AnyFilter::Tcp(Box::new(StubTcpFilter));
74        assert_eq!(
75            f.protocol_level(),
76            ProtocolKind::Tcp,
77            "Tcp variant should report Tcp protocol"
78        );
79    }
80
81    #[test]
82    fn http_variant_name() {
83        let f = AnyFilter::Http(Box::new(StubHttpFilter));
84        assert_eq!(
85            f.name(),
86            "stub_http",
87            "Http variant should delegate name to inner filter"
88        );
89    }
90
91    #[test]
92    fn tcp_variant_name() {
93        let f = AnyFilter::Tcp(Box::new(StubTcpFilter));
94        assert_eq!(f.name(), "stub_tcp", "Tcp variant should delegate name to inner filter");
95    }
96
97    // -------------------------------------------------------------------------
98    // Test Utilities
99    // -------------------------------------------------------------------------
100
101    /// Stub HTTP filter for protocol level tests.
102    struct StubHttpFilter;
103
104    #[async_trait]
105    impl HttpFilter for StubHttpFilter {
106        fn name(&self) -> &'static str {
107            "stub_http"
108        }
109
110        async fn on_request(&self, _ctx: &mut HttpFilterContext<'_>) -> Result<FilterAction, FilterError> {
111            Ok(FilterAction::Continue)
112        }
113    }
114
115    /// Stub TCP filter for protocol level tests.
116    struct StubTcpFilter;
117
118    #[async_trait]
119    impl TcpFilter for StubTcpFilter {
120        fn name(&self) -> &'static str {
121            "stub_tcp"
122        }
123    }
124}