redirectionio 3.1.0

Redirection IO Library to handle matching rule, redirect and filtering headers and body.
Documentation
use std::collections::HashMap;

use serde::{Deserialize, Serialize};

use crate::{api::Transformer, http::Request};

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
pub enum VariableKind {
    Marker(String),
    RequestHeader {
        name: String,
        default: Option<String>,
    },
    RequestHost,
    RequestMethod,
    RequestPath,
    RequestRemoteAddress,
    RequestScheme,
    RequestTime,
    HtmlBody {
        selector: String,
        default: Option<String>,
    },
    #[serde(untagged)]
    Other(serde_json::Value),
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Variable {
    pub name: String,
    #[serde(rename = "type")]
    kind: VariableKind,
    #[serde(skip_serializing_if = "Vec::is_empty", default)]
    transformers: Vec<Transformer>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum VariableValue {
    Value(String),
    HtmlFilter {
        selector: String,
        default: Option<String>,
        transformers: Vec<Transformer>,
    },
}

impl Variable {
    pub fn get_value(&self, markers_captured: &HashMap<String, String>, request: &Request) -> VariableValue {
        let mut value = match &self.kind {
            VariableKind::RequestHeader { name, default } => Some(
                request
                    .header_value(name.as_str())
                    .unwrap_or_else(|| default.clone().unwrap_or_default()),
            ),
            VariableKind::RequestHost => request.host.clone(),
            VariableKind::RequestMethod => request.method.clone(),
            VariableKind::RequestPath => Some(request.path_and_query_skipped.original.clone()),
            VariableKind::RequestRemoteAddress => request.remote_addr.map(|addr| addr.to_string()),
            VariableKind::RequestScheme => request.scheme.clone(),
            VariableKind::RequestTime => request.created_at.map(|d| d.to_rfc2822()),
            VariableKind::Marker(marker_name) => markers_captured.get(marker_name.as_str()).cloned(),
            VariableKind::HtmlBody { selector, default } => {
                return VariableValue::HtmlFilter {
                    selector: selector.clone(),
                    default: default.clone(),
                    transformers: self.transformers.clone(),
                };
            }
            VariableKind::Other(_) => None,
        }
        .unwrap_or_default();

        for transformer in &self.transformers {
            match transformer.to_transform() {
                None => (),
                Some(t) => {
                    value = t.transform(value);
                }
            }
        }

        VariableValue::Value(value)
    }
}

impl VariableValue {
    pub fn to_static(&self, mut new_value: String) -> VariableValue {
        match self {
            VariableValue::Value(_) => VariableValue::Value(new_value),
            VariableValue::HtmlFilter { transformers, .. } => {
                for transformer in transformers {
                    match transformer.to_transform() {
                        None => (),
                        Some(t) => {
                            new_value = t.transform(new_value);
                        }
                    }
                }

                VariableValue::Value(new_value)
            }
        }
    }
}