use http::header::{HeaderName, HeaderValue};
use http::HttpTryFrom;
use std::fmt;
use std::marker::PhantomData;
use endpoint::with_get_cx;
use endpoint::{ApplyContext, ApplyError, ApplyResult, Endpoint};
use error;
use error::Error;
use input::FromHeaderValue;
#[inline]
pub fn parse<T>(name: &'static str) -> Parse<T>
where
T: FromHeaderValue,
{
(Parse {
name: HeaderName::from_static(name),
_marker: PhantomData,
}).with_output::<(T,)>()
}
#[allow(missing_docs)]
pub struct Parse<T> {
name: HeaderName,
_marker: PhantomData<fn() -> T>,
}
impl<T> fmt::Debug for Parse<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Parse").field("name", &self.name).finish()
}
}
impl<'e, T> Endpoint<'e> for Parse<T>
where
T: FromHeaderValue,
{
type Output = (T,);
type Future = ParseFuture<'e, T>;
fn apply(&'e self, cx: &mut ApplyContext<'_>) -> ApplyResult<Self::Future> {
if cx.input().headers().contains_key(&self.name) {
Ok(ParseFuture { endpoint: self })
} else {
Err(ApplyError::custom(error::bad_request(format!(
"missing header: `{}'",
self.name.as_str()
))))
}
}
}
#[doc(hidden)]
#[derive(Debug)]
pub struct ParseFuture<'e, T: 'e> {
endpoint: &'e Parse<T>,
}
impl<'e, T> ::futures::Future for ParseFuture<'e, T>
where
T: FromHeaderValue,
{
type Item = (T,);
type Error = Error;
fn poll(&mut self) -> ::futures::Poll<Self::Item, Self::Error> {
with_get_cx(|input| {
let h = input
.headers()
.get(&self.endpoint.name)
.expect("The header value should be always available inside of this Future.");
T::from_header_value(h)
.map(|parsed| (parsed,).into())
.map_err(error::bad_request)
})
}
}
#[inline]
pub fn optional<T>(name: &'static str) -> Optional<T>
where
T: FromHeaderValue,
{
(Optional {
name: HeaderName::from_static(name),
_marker: PhantomData,
}).with_output::<(Option<T>,)>()
}
#[allow(missing_docs)]
pub struct Optional<T> {
name: HeaderName,
_marker: PhantomData<fn() -> T>,
}
impl<T> fmt::Debug for Optional<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Optional")
.field("name", &self.name)
.finish()
}
}
impl<'e, T> Endpoint<'e> for Optional<T>
where
T: FromHeaderValue,
{
type Output = (Option<T>,);
type Future = OptionalFuture<'e, T>;
fn apply(&'e self, _: &mut ApplyContext<'_>) -> ApplyResult<Self::Future> {
Ok(OptionalFuture { endpoint: self })
}
}
#[doc(hidden)]
#[derive(Debug)]
pub struct OptionalFuture<'e, T: 'e> {
endpoint: &'e Optional<T>,
}
impl<'e, T> ::futures::Future for OptionalFuture<'e, T>
where
T: FromHeaderValue,
{
type Item = (Option<T>,);
type Error = Error;
fn poll(&mut self) -> ::futures::Poll<Self::Item, Self::Error> {
with_get_cx(|input| match input.headers().get(&self.endpoint.name) {
Some(h) => T::from_header_value(h)
.map(|parsed| (Some(parsed),).into())
.map_err(error::bad_request),
None => Ok((None,).into()),
})
}
}
#[inline]
pub fn matches<K, V>(name: K, value: V) -> Matches<V>
where
HeaderName: HttpTryFrom<K>,
<HeaderName as HttpTryFrom<K>>::Error: fmt::Debug,
V: PartialEq<HeaderValue>,
{
(Matches {
name: HeaderName::try_from(name).expect("invalid header name"),
value,
}).with_output::<()>()
}
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct Matches<V> {
name: HeaderName,
value: V,
}
impl<'e, V> Endpoint<'e> for Matches<V>
where
V: PartialEq<HeaderValue> + 'e,
{
type Output = ();
type Future = ::futures::future::FutureResult<Self::Output, Error>;
fn apply(&'e self, ecx: &mut ApplyContext<'_>) -> ApplyResult<Self::Future> {
match ecx.input().headers().get(&self.name) {
Some(value) if self.value == *value => Ok(::futures::future::result(Ok(()))),
_ => Err(ApplyError::not_matched()),
}
}
}
#[inline]
pub fn raw<H>(name: H) -> Raw
where
HeaderName: HttpTryFrom<H>,
<HeaderName as HttpTryFrom<H>>::Error: fmt::Debug,
{
(Raw {
name: HeaderName::try_from(name).expect("invalid header name"),
}).with_output::<(Option<HeaderValue>,)>()
}
#[allow(missing_docs)]
#[derive(Debug)]
pub struct Raw {
name: HeaderName,
}
impl<'a> Endpoint<'a> for Raw {
type Output = (Option<HeaderValue>,);
type Future = ::futures::future::FutureResult<Self::Output, Error>;
fn apply(&'a self, cx: &mut ApplyContext<'_>) -> ApplyResult<Self::Future> {
let header = cx.input().headers().get(&self.name).cloned();
Ok(::futures::future::result(Ok((header,))))
}
}