From f7ef8ae5a5831fabc9aa176f1927c2698c5bb375 Mon Sep 17 00:00:00 2001
From: Nikolay Kim <fafhrd91@gmail.com>
Date: Thu, 7 Jun 2018 20:00:54 -0700
Subject: [PATCH] add Host predicate

---
 src/application.rs |  2 +-
 src/pred.rs        | 61 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/src/application.rs b/src/application.rs
index c9171008..eb078746 100644
--- a/src/application.rs
+++ b/src/application.rs
@@ -306,7 +306,7 @@ where
     /// # use actix_web::*;
     /// # fn main() {
     /// App::new()
-    ///     .filter(pred::Get())
+    ///     .filter(pred::Hoat("www.rust-lang.org"))
     ///     .resource("/path", |r| r.f(|_| HttpResponse::Ok()))
     /// #      .finish();
     /// # }
diff --git a/src/pred.rs b/src/pred.rs
index 206a7941..020052e2 100644
--- a/src/pred.rs
+++ b/src/pred.rs
@@ -196,6 +196,45 @@ impl<S: 'static> Predicate<S> for HeaderPredicate<S> {
     }
 }
 
+/// Return predicate that matches if request contains specified Host name.
+///
+/// ```rust
+/// # extern crate actix_web;
+/// use actix_web::{pred, App, HttpResponse};
+///
+/// fn main() {
+///     App::new().resource("/index.html", |r| {
+///         r.route()
+///             .filter(pred::Host("www.rust-lang.org"))
+///             .f(|_| HttpResponse::MethodNotAllowed())
+///     });
+/// }
+/// ```
+pub fn Host<S: 'static, H: AsRef<str>>(host: H) -> HostPredicate<S> {
+    HostPredicate(host.as_ref().to_string(), None, PhantomData)
+}
+
+#[doc(hidden)]
+pub struct HostPredicate<S>(String, Option<String>, PhantomData<S>);
+
+impl<S> HostPredicate<S> {
+    /// Set reuest scheme to match
+    pub fn scheme<H: AsRef<str>>(&mut self, scheme: H) {
+        self.1 = Some(scheme.as_ref().to_string())
+    }
+}
+
+impl<S: 'static> Predicate<S> for HostPredicate<S> {
+    fn check(&self, req: &mut HttpRequest<S>) -> bool {
+        let info = req.connection_info();
+        if let Some(ref scheme) = self.1 {
+            self.0 == info.host() && scheme == info.scheme()
+        } else {
+            self.0 == info.host()
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -228,6 +267,28 @@ mod tests {
         assert!(!pred.check(&mut req));
     }
 
+    #[test]
+    fn test_host() {
+        let mut headers = HeaderMap::new();
+        headers.insert(
+            header::HOST,
+            header::HeaderValue::from_static("www.rust-lang.org"),
+        );
+        let mut req = HttpRequest::new(
+            Method::GET,
+            Uri::from_str("/").unwrap(),
+            Version::HTTP_11,
+            headers,
+            None,
+        );
+
+        let pred = Host("www.rust-lang.org");
+        assert!(pred.check(&mut req));
+
+        let pred = Host("localhost");
+        assert!(!pred.check(&mut req));
+    }
+
     #[test]
     fn test_methods() {
         let mut req = HttpRequest::new(