1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
use std::sync::Arc;

use log::error;
use crate::http::*;
use crate::utils::{RequestContinuation, UriPathMatcher};
use crate::utils::RequestContinuation::*;

///
pub struct Builder {
    stack: Vec<(MiddlewareRule, Box<dyn Middleware>)>,
}

impl Builder {
    /// Creates a new MiddlewareStack Builder
    pub fn new() -> Self {
        Builder {
            stack: Vec::new()
        }
    }

    /// Method to apply a new middleware onto the stack where the `include_path` vec are all path affected by the middleware,
    /// and `exclude_path` are exclusion amongst the included paths.
    pub fn apply<M: 'static + Middleware>(mut self, m: M, include_path: Vec<&str>, exclude_path: Option<Vec<&str>>) -> Self {
        let rule = MiddlewareRule::new(include_path, exclude_path);
        let boxed_m = Box::new(m);

        self.stack.push((rule, boxed_m));

        self
    }

    /// Build the middleware stack
    pub fn build(self) -> MiddlewareStack {
        let Builder {
            stack,
        } = self;

        MiddlewareStack {
            middlewares: Arc::new(stack),
        }
    }
}

/// Struct representing the layering of middlewares in the server
pub struct MiddlewareStack {
    middlewares: Arc<Vec<(MiddlewareRule, Box<dyn Middleware>)>>
}

impl MiddlewareStack {
    ///
    pub fn new() -> Self {
        MiddlewareStack {
            middlewares: Arc::new(Vec::new())
        }
    }

    ///
    pub fn resolve(&self, req: &mut SyncRequest, res: &mut SyncResponse) -> RequestContinuation {
        for &(ref rule, ref middleware) in self.middlewares.iter() {
            if rule.validate_path(req.uri().path()) {
                if let Stop = middleware.resolve(req, res) {
                    return Stop;
                }
            }
        }

        Continue
    }
}

impl Clone for MiddlewareStack {
    fn clone(&self) -> Self {
        MiddlewareStack {
            middlewares: self.middlewares.clone(),
        }
    }
}

/// The trait a struct need to `impl` to be considered as a middleware
pub trait Middleware: Send + Sync {
    /// This method will be invoked if the request is targeting an included path, (as defined when "applying" the middleware to the stack)
    /// and doesn't match any exclusion. Returning `RequestContinuation::Continue` will allow the request to continue through the stack, and
    /// returning `RequestContinuation::Stop` will cease the request processing, returning as response the modified `res` param.
    fn resolve(&self, req: &mut SyncRequest, res: &mut SyncResponse) -> RequestContinuation;
}

struct MiddlewareRule {
    included_path: Vec<UriPathMatcher>,
    excluded_path: Option<Vec<UriPathMatcher>>,
}

impl MiddlewareRule {
    pub fn new(include_path: Vec<&str>, exclude_path: Option<Vec<&str>>) -> Self {
        MiddlewareRule {
            included_path: include_path.iter().filter_map(|p| UriPathMatcher::new(p).map_err(|e| error!("Unable to construct included middleware route: {}", e)).ok()).collect(),
            excluded_path: exclude_path.map(|ex| ex.iter().filter_map(|p| UriPathMatcher::new(p).map_err(|e| error!("Unable to construct excluded middleware route: {}", e)).ok()).collect()),
        }
    }

    pub fn validate_path(&self, path: &str) -> bool {
        if self.included_path.iter().any(|m_p| m_p.match_start(path)) {
            if let Some(ref excluded_path) = self.excluded_path {
                return !excluded_path.iter().any(|m_e_p| m_e_p.match_start(path));
            } else {
                return true;
            }
        }

        false
    }
}