use crate::filter::{filter_fn_one, Filter, One};
use crate::reject::{self, Rejection};
use futures::future;
pub use http::uri::Authority;
use std::str::FromStr;
pub fn exact(expected: &str) -> impl Filter<Extract = (), Error = Rejection> + Clone {
let expected = Authority::from_str(expected).expect("invalid host/authority");
optional()
.and_then(move |option: Option<Authority>| match option {
Some(authority) if authority == expected => future::ok(()),
_ => future::err(reject::not_found()),
})
.untuple_one()
}
pub fn optional() -> impl Filter<Extract = One<Option<Authority>>, Error = Rejection> + Copy {
filter_fn_one(move |route| {
let from_uri = route.uri().authority();
let name = "host";
let from_header = route.headers()
.get(name)
.map(|value|
value.to_str().map_err(|_| reject::invalid_header(name))
.and_then(|value| Authority::from_str(value).map_err(|_| reject::invalid_header(name)))
);
future::ready(match (from_uri, from_header) {
(None, None) => Ok(None),
(Some(a), None) => Ok(Some(a.clone())),
(None, Some(Ok(a))) => Ok(Some(a)),
(Some(a), Some(Ok(b))) if *a == b => Ok(Some(b)),
(Some(_), Some(Ok(_))) => Err(reject::invalid_header(name)),
(_, Some(Err(r))) => Err(r),
})
})
}