summaryrefslogtreecommitdiff
path: root/src/modules
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules')
-rw-r--r--src/modules/mod.rs3
-rw-r--r--src/modules/redirect.rs50
2 files changed, 53 insertions, 0 deletions
diff --git a/src/modules/mod.rs b/src/modules/mod.rs
index 0fe9ca0..00425bf 100644
--- a/src/modules/mod.rs
+++ b/src/modules/mod.rs
@@ -12,6 +12,7 @@ use hosts::HostsKind;
use http_body_util::combinators::BoxBody;
use hyper::{body::Incoming, Request, Response};
use proxy::ProxyKind;
+use redirect::RedirectKind;
use serde_yaml::Value;
use std::{net::SocketAddr, pin::Pin, sync::Arc};
use switch::SwitchKind;
@@ -24,6 +25,7 @@ pub mod files;
pub mod headers;
pub mod hosts;
pub mod proxy;
+pub mod redirect;
pub mod switch;
pub type NodeRequest = Request<Incoming>;
@@ -40,6 +42,7 @@ pub static MODULES: &[&dyn NodeKind] = &[
&ErrorKind,
&HeadersKind,
&SwitchKind,
+ &RedirectKind,
];
pub struct NodeContext {
diff --git a/src/modules/redirect.rs b/src/modules/redirect.rs
new file mode 100644
index 0000000..e3fa599
--- /dev/null
+++ b/src/modules/redirect.rs
@@ -0,0 +1,50 @@
+use super::{Node, NodeContext, NodeKind, NodeRequest, NodeResponse};
+use crate::error::ServiceError;
+use anyhow::Result;
+use futures::Future;
+use http_body_util::BodyExt;
+use hyper::{header::HeaderValue, Response, StatusCode};
+use serde::Deserialize;
+use std::{pin::Pin, sync::Arc};
+
+pub struct RedirectKind;
+
+#[derive(Deserialize)]
+pub struct Redirect(HeaderValueWrap);
+
+impl NodeKind for RedirectKind {
+ fn name(&self) -> &'static str {
+ "redirect"
+ }
+ fn instanciate(&self, config: serde_yaml::Value) -> Result<Arc<dyn Node>> {
+ Ok(Arc::new(serde_yaml::from_value::<Redirect>(config)?))
+ }
+}
+
+impl Node for Redirect {
+ fn handle<'a>(
+ &'a self,
+ _context: &'a mut NodeContext,
+ _request: NodeRequest,
+ ) -> Pin<Box<dyn Future<Output = Result<NodeResponse, ServiceError>> + Send + Sync + 'a>> {
+ Box::pin(async move {
+ let mut resp = Response::new("".to_string()).map(|b| b.map_err(|e| match e {}).boxed());
+ *resp.status_mut() = StatusCode::MOVED_PERMANENTLY;
+ resp.headers_mut().insert("Location", self.0 .0.clone());
+ Ok(resp)
+ })
+ }
+}
+
+struct HeaderValueWrap(HeaderValue);
+impl<'de> Deserialize<'de> for HeaderValueWrap {
+ fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ let s = String::deserialize(deserializer)?;
+ Ok(HeaderValueWrap(
+ HeaderValue::from_str(&s).map_err(|e| serde::de::Error::custom(format!("{e}")))?,
+ ))
+ }
+}