/* This file is part of gnix (https://codeberg.org/metamuffin/gnix) which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2025 metamuffin */ use super::{Node, NodeContext, NodeKind, NodeRequest, NodeResponse}; use crate::{config::DynNode, error::ServiceError}; use anyhow::Result; use futures::Future; use hyper::{ header::{HeaderName, HeaderValue}, HeaderMap, }; use serde::Deserialize; use std::{collections::BTreeMap, pin::Pin, str::FromStr, sync::Arc}; pub struct HeadersKind; #[derive(Deserialize)] pub struct Headers { #[serde(default)] request: HeaderMapWrap, #[serde(default)] response: HeaderMapWrap, next: DynNode, } impl NodeKind for HeadersKind { fn name(&self) -> &'static str { "headers" } fn instanciate(&self, config: serde_yml::Value) -> Result> { Ok(Arc::new(serde_yml::from_value::(config)?)) } } impl Node for Headers { fn handle<'a>( &'a self, context: &'a mut NodeContext, mut request: NodeRequest, ) -> Pin> + Send + Sync + 'a>> { Box::pin(async move { request .headers_mut() .extend(self.request.0.clone()); let mut response = self.next.handle(context, request).await?; response .headers_mut() .extend(self.response.0.clone()); Ok(response) }) } } #[derive(Default)] struct HeaderMapWrap(HeaderMap); impl<'de> Deserialize<'de> for HeaderMapWrap { fn deserialize(deserializer: D) -> std::result::Result where D: serde::Deserializer<'de>, { let headers = BTreeMap::::deserialize(deserializer)?; let mut hm = HeaderMap::new(); for (k, v) in headers { hm.insert( HeaderName::from_str(&k).map_err(|e| serde::de::Error::custom(format!("{e}")))?, HeaderValue::from_str(&v).map_err(|e| serde::de::Error::custom(format!("{e}")))?, ); } Ok(HeaderMapWrap(hm)) } }