//! Route match predicates #![allow(non_snake_case)] use std::marker::PhantomData; use http; use http::{header, HttpTryFrom}; use httprequest::HttpRequest; /// Trait defines resource route predicate. /// Predicate can modify request object. It is also possible to /// to store extra attributes on request by using `.extensions()` method. pub trait Predicate { /// Check if request matches predicate fn check(&self, &mut HttpRequest) -> bool; } /// Return predicate that matches if any of supplied predicate matches. pub fn Any(preds: T) -> Box> where T: IntoIterator>> { Box::new(AnyPredicate(preds.into_iter().collect())) } struct AnyPredicate(Vec>>); impl Predicate for AnyPredicate { fn check(&self, req: &mut HttpRequest) -> bool { for p in &self.0 { if p.check(req) { return true } } false } } /// Return predicate that matches if all of supplied predicate matches. pub fn All(preds: T) -> Box> where T: IntoIterator>> { Box::new(AllPredicate(preds.into_iter().collect())) } struct AllPredicate(Vec>>); impl Predicate for AllPredicate { fn check(&self, req: &mut HttpRequest) -> bool { for p in &self.0 { if !p.check(req) { return false } } true } } /// Return predicate that matches if supplied predicate does not match. pub fn Not(pred: Box>) -> Box> { Box::new(NotPredicate(pred)) } struct NotPredicate(Box>); impl Predicate for NotPredicate { fn check(&self, req: &mut HttpRequest) -> bool { !self.0.check(req) } } /// Http method predicate struct MethodPredicate(http::Method, PhantomData); impl Predicate for MethodPredicate { fn check(&self, req: &mut HttpRequest) -> bool { *req.method() == self.0 } } /// Predicate to match *GET* http method pub fn Get() -> Box> { Box::new(MethodPredicate(http::Method::GET, PhantomData)) } /// Predicate to match *POST* http method pub fn Post() -> Box> { Box::new(MethodPredicate(http::Method::POST, PhantomData)) } /// Predicate to match *PUT* http method pub fn Put() -> Box> { Box::new(MethodPredicate(http::Method::PUT, PhantomData)) } /// Predicate to match *DELETE* http method pub fn Delete() -> Box> { Box::new(MethodPredicate(http::Method::DELETE, PhantomData)) } /// Predicate to match *HEAD* http method pub fn Head() -> Box> { Box::new(MethodPredicate(http::Method::HEAD, PhantomData)) } /// Predicate to match *OPTIONS* http method pub fn Options() -> Box> { Box::new(MethodPredicate(http::Method::OPTIONS, PhantomData)) } /// Predicate to match *CONNECT* http method pub fn Connect() -> Box> { Box::new(MethodPredicate(http::Method::CONNECT, PhantomData)) } /// Predicate to match *PATCH* http method pub fn Patch() -> Box> { Box::new(MethodPredicate(http::Method::PATCH, PhantomData)) } /// Predicate to match *TRACE* http method pub fn Trace() -> Box> { Box::new(MethodPredicate(http::Method::TRACE, PhantomData)) } /// Predicate to match specified http method pub fn Method(method: http::Method) -> Box> { Box::new(MethodPredicate(method, PhantomData)) } /// Return predicate that matches if request contains specified header and value. pub fn Header(name: &'static str, value: &'static str) -> Box> { Box::new(HeaderPredicate(header::HeaderName::try_from(name).unwrap(), header::HeaderValue::from_static(value), PhantomData)) } struct HeaderPredicate(header::HeaderName, header::HeaderValue, PhantomData); impl Predicate for HeaderPredicate { fn check(&self, req: &mut HttpRequest) -> bool { if let Some(val) = req.headers().get(&self.0) { return val == self.1 } false } }