diff options
author | metamuffin <metamuffin@disroot.org> | 2025-02-05 12:45:56 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-02-05 12:45:56 +0100 |
commit | 27a503c1a92c8f8b0e398187d58e677ecf68e915 (patch) | |
tree | 505393926d7208dd3e5c9acd923f140b6a60259a | |
parent | 65ceb5683340726ff2ee831181dd9d60da2456b3 (diff) | |
download | gnix-27a503c1a92c8f8b0e398187d58e677ecf68e915.tar gnix-27a503c1a92c8f8b0e398187d58e677ecf68e915.tar.bz2 gnix-27a503c1a92c8f8b0e398187d58e677ecf68e915.tar.zst |
fallback handler
-rw-r--r-- | readme.md | 9 | ||||
-rw-r--r-- | src/main.rs | 5 | ||||
-rw-r--r-- | src/modules/fallback.rs | 61 | ||||
-rw-r--r-- | src/modules/mod.rs | 6 |
4 files changed, 78 insertions, 3 deletions
@@ -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 { |