use super::{Node, NodeContext, NodeKind, NodeRequest, NodeResponse}; use crate::{config::DynNode, error::ServiceError}; use futures::Future; use hyper::header::HOST; use serde::Deserialize; use serde_yaml::Value; use std::{collections::HashMap, pin::Pin, sync::Arc}; #[derive(Deserialize)] #[serde(transparent)] struct Hosts(HashMap); pub struct HostsKind; impl NodeKind for HostsKind { fn name(&self) -> &'static str { "hosts" } fn instanciate(&self, config: Value) -> anyhow::Result> { Ok(Arc::new(serde_yaml::from_value::(config)?)) } } impl Node for Hosts { fn handle<'a>( &'a self, context: &'a mut NodeContext, request: NodeRequest, ) -> Pin> + Send + Sync + 'a>> { Box::pin(async move { // use Host header but if missing like in HTTP/2 uses uri authority let host = request .headers() .get(HOST) .and_then(|e| e.to_str().ok()) .map(remove_port) .or(request.uri().authority().map(|a| a.host())) .ok_or(ServiceError::NoHost)?; let node = self.0.get(host).ok_or(ServiceError::UnknownHost)?; node.handle(context, request).await }) } } pub fn remove_port(s: &str) -> &str { s.split_once(":").map(|(s, _)| s).unwrap_or(s) }