summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-02-05 12:45:56 +0100
committermetamuffin <metamuffin@disroot.org>2025-02-05 12:45:56 +0100
commit27a503c1a92c8f8b0e398187d58e677ecf68e915 (patch)
tree505393926d7208dd3e5c9acd923f140b6a60259a
parent65ceb5683340726ff2ee831181dd9d60da2456b3 (diff)
downloadgnix-27a503c1a92c8f8b0e398187d58e677ecf68e915.tar
gnix-27a503c1a92c8f8b0e398187d58e677ecf68e915.tar.bz2
gnix-27a503c1a92c8f8b0e398187d58e677ecf68e915.tar.zst
fallback handler
-rw-r--r--readme.md9
-rw-r--r--src/main.rs5
-rw-r--r--src/modules/fallback.rs61
-rw-r--r--src/modules/mod.rs6
4 files changed, 78 insertions, 3 deletions
diff --git a/readme.md b/readme.md
index e558ace..cd5e5d8 100644
--- a/readme.md
+++ b/readme.md
@@ -219,6 +219,15 @@ themselves; in that case the request is passed on.
this.**
- Takes a set of handlers. (sequence of module)
+- **module `fallback`**
+ - Runs a series of handlers until one returns a success, informational or
+ redirect response and the returns that. The last handler's response will
+ unconditionally be returned. Note that to run multiple handlers the request
+ body will first be completely received to memory before any handler is run.
+ There is currently no size limit for request bodies, so be careful using
+ this. **TODO request size limit**
+ - Takes a sequence of handlers.
+
- **module `debug`**
- Replies with information about the request to debug. Includes source
address, HTTP version, URI and headers.
diff --git a/src/main.rs b/src/main.rs
index a3edd28..c3e8cc7 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -242,7 +242,10 @@ async fn service(
);
let mut context = NodeContext { addr, state };
- let mut resp = config.handler.handle(&mut context, request).await?;
+ let mut resp = config
+ .handler
+ .handle(&mut context, request.map(|body| body.boxed()))
+ .await?;
let server_header = resp.headers().get(SERVER).cloned();
resp.headers_mut().insert(
diff --git a/src/modules/fallback.rs b/src/modules/fallback.rs
new file mode 100644
index 0000000..b0deed1
--- /dev/null
+++ b/src/modules/fallback.rs
@@ -0,0 +1,61 @@
+use super::{Node, NodeContext, NodeKind, NodeRequest, NodeResponse};
+use crate::{config::DynNode, error::ServiceError};
+use anyhow::Result;
+use http::Request;
+use http_body_util::{combinators::BoxBody, BodyExt, Full};
+use serde::Deserialize;
+use serde_yml::Value;
+use std::{future::Future, pin::Pin, sync::Arc};
+
+pub struct FallbackKind;
+
+#[derive(Deserialize)]
+struct Fallback(Vec<DynNode>);
+
+impl NodeKind for FallbackKind {
+ fn name(&self) -> &'static str {
+ "fallback"
+ }
+ fn instanciate(&self, config: Value) -> Result<Arc<dyn Node>> {
+ Ok(Arc::new(serde_yml::from_value::<Fallback>(config)?))
+ }
+}
+impl Node for Fallback {
+ 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 (parts, body) = request.into_parts();
+ let body = body
+ .collect()
+ .await
+ .map_err(|_| ServiceError::Other)?
+ .to_bytes();
+
+ for (i, h) in self.0.iter().enumerate() {
+ let last = i == self.0.len() - 1;
+ let resp = h
+ .handle(
+ context,
+ Request::from_parts(
+ parts.clone(),
+ BoxBody::new(Full::new(body.clone()).map_err(|x| match x {})),
+ ),
+ )
+ .await?;
+ if resp.status().is_success()
+ || resp.status().is_redirection()
+ || resp.status().is_informational()
+ || last
+ {
+ return Ok(resp);
+ }
+ }
+ return Err(ServiceError::CustomStatic(
+ "fallback module without any handlers",
+ ));
+ })
+ }
+}
diff --git a/src/modules/mod.rs b/src/modules/mod.rs
index 6f945af..97dee1a 100644
--- a/src/modules/mod.rs
+++ b/src/modules/mod.rs
@@ -3,7 +3,7 @@ use crate::State;
use bytes::Bytes;
use futures::Future;
use http_body_util::combinators::BoxBody;
-use hyper::{body::Incoming, Request, Response};
+use hyper::{Request, Response};
use serde_yml::Value;
use std::{net::SocketAddr, pin::Pin, sync::Arc};
@@ -13,6 +13,7 @@ mod cache;
mod cgi;
mod debug;
mod error;
+pub mod fallback;
mod file;
mod files;
mod headers;
@@ -25,7 +26,7 @@ mod redirect;
mod switch;
mod upgrade_insecure;
-pub type NodeRequest = Request<Incoming>;
+pub type NodeRequest = Request<BoxBody<Bytes, hyper::Error>>;
pub type NodeResponse = Response<BoxBody<Bytes, ServiceError>>;
pub static MODULES: &[&dyn NodeKind] = &[
@@ -48,6 +49,7 @@ pub static MODULES: &[&dyn NodeKind] = &[
&loadbalance::LoadBalanceKind,
&upgrade_insecure::UpgradeInsecureKind,
&inspect::InspectKind,
+ &fallback::FallbackKind,
];
pub struct NodeContext {