httproxide 0.2.0

Rusted HTTP router reverse-proxy
Documentation
#[cfg(feature = "auth-layer")]
pub mod auth;
#[cfg(feature = "auth-request-layer")]
pub mod auth_request;
#[cfg(feature = "ip-filter-layer")]
pub mod ip_filter;
#[cfg(feature = "limit-layer")]
pub mod limit;
#[cfg(feature = "set-header-layer")]
pub mod set_header;
#[cfg(feature = "set-status-layer")]
pub mod set_status;

use serde::{Deserialize, Serialize};
use tower::Layer;

use crate::target::{IntoTarget, Target};

pub trait ApplyLayer {
    fn apply_layer(&self, t: Target) -> Target;
}

impl<L> ApplyLayer for L
where
    L: Layer<Target>,
    L::Service: IntoTarget,
{
    fn apply_layer(&self, t: Target) -> Target {
        self.layer(t).into_target()
    }
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[serde(tag = "layer_type")]
pub enum BuiltinLayerConfig {
    #[cfg(feature = "auth-layer")]
    RequireBasicAuth(auth::RequireBasicAuthConfig),
    #[cfg(feature = "auth-layer")]
    RequireBearerAuth(auth::RequireBearerAuthConfig),
    #[cfg(feature = "auth-request-layer")]
    AuthRequest(auth_request::AuthRequestConfig),
    #[cfg(feature = "set-header-layer")]
    SetResponseHeader(set_header::SetHeaderConfig),
    #[cfg(feature = "set-header-layer")]
    SetRequestHeader(set_header::SetHeaderConfig),
    #[cfg(feature = "set-status-layer")]
    SetStatus(set_status::SetStatusConfig),
    #[cfg(feature = "ip-filter-layer")]
    IpFilter(ip_filter::IpFilterConfig),
    #[cfg(feature = "limit-layer")]
    RequestBodyLimit(limit::RequestBodyLimitConfig),
}

pub fn layer_config(s: Target, cfg: serde_yaml::Value) -> anyhow::Result<Target> {
    let target = match serde_yaml::from_value(cfg) {
        Ok(builtin) => match builtin {
            #[cfg(feature = "auth-layer")]
            BuiltinLayerConfig::RequireBasicAuth(config) => {
                auth::basic_from_config(config)?.apply_layer(s)
            }
            #[cfg(feature = "auth-layer")]
            BuiltinLayerConfig::RequireBearerAuth(config) => {
                auth::bearer_from_config(config)?.apply_layer(s)
            }
            #[cfg(feature = "auth-request-layer")]
            BuiltinLayerConfig::AuthRequest(config) => {
                auth_request::from_config(config)?.apply_layer(s)
            }
            #[cfg(feature = "set-header-layer")]
            BuiltinLayerConfig::SetResponseHeader(config) => {
                set_header::response_from_config(config)?.apply_layer(s)
            }
            #[cfg(feature = "set-header-layer")]
            BuiltinLayerConfig::SetRequestHeader(config) => {
                set_header::request_from_config(config)?.apply_layer(s)
            }
            #[cfg(feature = "set-status-layer")]
            BuiltinLayerConfig::SetStatus(config) => {
                set_status::from_config(config)?.apply_layer(s)
            }
            #[cfg(feature = "ip-filter-layer")]
            BuiltinLayerConfig::IpFilter(config) => ip_filter::from_config(config)?.apply_layer(s),
            #[cfg(feature = "limit-layer")]
            BuiltinLayerConfig::RequestBodyLimit(config) => {
                limit::from_config(config)?.apply_layer(s)
            }
        },
        Err(e) => anyhow::bail!("{}", e),
    };
    Ok(target)
}

pub fn layers_config(
    mut s: Target,
    cfg: impl IntoIterator<Item = serde_yaml::Value>,
) -> anyhow::Result<Target> {
    for layer in cfg.into_iter() {
        s = layer_config(s, layer)?;
    }
    Ok(s)
}