From 4da8fe84c07e3f9e83f9b769f1670f4d52466001 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Sat, 22 Jun 2024 12:54:39 +0200 Subject: add switch module --- src/modules/headers.rs | 6 ++--- src/modules/mod.rs | 3 +++ src/modules/switch.rs | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 src/modules/switch.rs (limited to 'src') diff --git a/src/modules/headers.rs b/src/modules/headers.rs index b1e452e..ad4595a 100644 --- a/src/modules/headers.rs +++ b/src/modules/headers.rs @@ -1,4 +1,4 @@ -use super::{Node, NodeKind, NodeResponse}; +use super::{Node, NodeContext, NodeKind, NodeRequest, NodeResponse}; use crate::{config::DynNode, error::ServiceError}; use anyhow::Result; use futures::Future; @@ -29,8 +29,8 @@ impl NodeKind for HeadersKind { impl Node for Headers { fn handle<'a>( &'a self, - context: &'a mut super::NodeContext, - request: super::NodeRequest, + context: &'a mut NodeContext, + request: NodeRequest, ) -> Pin> + Send + Sync + 'a>> { Box::pin(async move { let mut resp = self.inner.handle(context, request).await?; diff --git a/src/modules/mod.rs b/src/modules/mod.rs index 2e08142..0fe9ca0 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -14,6 +14,7 @@ use hyper::{body::Incoming, Request, Response}; use proxy::ProxyKind; use serde_yaml::Value; use std::{net::SocketAddr, pin::Pin, sync::Arc}; +use switch::SwitchKind; pub mod accesslog; pub mod auth; @@ -23,6 +24,7 @@ pub mod files; pub mod headers; pub mod hosts; pub mod proxy; +pub mod switch; pub type NodeRequest = Request; pub type NodeResponse = Response>; @@ -37,6 +39,7 @@ pub static MODULES: &[&dyn NodeKind] = &[ &AccessLogKind, &ErrorKind, &HeadersKind, + &SwitchKind, ]; pub struct NodeContext { diff --git a/src/modules/switch.rs b/src/modules/switch.rs new file mode 100644 index 0000000..bbb9e98 --- /dev/null +++ b/src/modules/switch.rs @@ -0,0 +1,71 @@ +use super::{Node, NodeContext, NodeKind, NodeRequest, NodeResponse}; +use crate::{config::DynNode, error::ServiceError}; +use anyhow::Result; +use futures::Future; +use headers::{HeaderMapExt, Upgrade}; +use hyper::Method; +use serde::Deserialize; +use std::{pin::Pin, sync::Arc}; + +pub struct SwitchKind; + +#[derive(Deserialize)] +pub struct Switch { + condition: Condition, + case_true: DynNode, + case_false: DynNode, +} + +impl NodeKind for SwitchKind { + fn name(&self) -> &'static str { + "switch" + } + fn instanciate(&self, config: serde_yaml::Value) -> Result> { + Ok(Arc::new(serde_yaml::from_value::(config)?)) + } +} + +impl Node for Switch { + fn handle<'a>( + &'a self, + context: &'a mut NodeContext, + request: NodeRequest, + ) -> Pin> + Send + Sync + 'a>> { + Box::pin(async move { + let cond = self.condition.test(&request); + if cond { + &self.case_true + } else { + &self.case_false + } + .handle(context, request) + .await + }) + } +} + +#[derive(Deserialize)] +#[serde(rename_all = "snake_case")] +enum Condition { + IsWebsocketUpgrade, + IsPost, + IsGet, + HasHeader(String), + PathStartsWith(String), + PathIs(String), +} + +impl Condition { + pub fn test(&self, req: &NodeRequest) -> bool { + match self { + Condition::IsWebsocketUpgrade => { + req.headers().typed_get::() == Some(Upgrade::websocket()) + } + Condition::HasHeader(name) => req.headers().contains_key(name), + Condition::PathStartsWith(path_prefix) => req.uri().path().starts_with(path_prefix), + Condition::PathIs(path) => req.uri().path() == path, + Condition::IsPost => req.method() == Method::POST, + Condition::IsGet => req.method() == Method::GET, + } + } +} -- cgit v1.2.3-70-g09d2