use std::fmt; use control::destination::{Metadata, ProtocolHint}; use proxy::http::settings; use svc; use tap; use transport::{connect, tls}; use NameAddr; #[derive(Clone, Debug)] pub struct Endpoint { pub dst_name: Option, pub connect: connect::Target, pub metadata: Metadata, } // === impl Endpoint === impl Endpoint { pub fn can_use_orig_proto(&self) -> bool { match self.metadata.protocol_hint() { ProtocolHint::Unknown => false, ProtocolHint::Http2 => true, } } } impl settings::router::HasConnect for Endpoint { fn connect(&self) -> connect::Target { self.connect.clone() } } impl fmt::Display for Endpoint { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.connect.addr.fmt(f) } } impl svc::watch::WithUpdate for Endpoint { type Updated = Self; fn with_update(&self, client_config: &tls::ConditionalClientConfig) -> Self::Updated { let mut ep = self.clone(); ep.connect.tls = ep.metadata.tls_identity().and_then(|identity| { client_config.as_ref().map(|config| tls::ConnectionConfig { server_identity: identity.clone(), config: config.clone(), }) }); ep } } impl From for tap::Endpoint { fn from(ep: Endpoint) -> Self { // TODO add route labels... tap::Endpoint { direction: tap::Direction::Out, labels: ep.metadata.labels().clone(), target: ep.connect.clone(), } } } pub mod discovery { use futures::{Async, Poll}; use std::net::SocketAddr; use super::super::dst::DstAddr; use super::Endpoint; use control::destination::Metadata; use proxy::resolve; use transport::{connect, tls}; use {Addr, Conditional, NameAddr}; #[derive(Clone, Debug)] pub struct Resolve>(R); #[derive(Debug)] pub enum Resolution { Name(NameAddr, R), Addr(Option), } // === impl Resolve === impl Resolve where R: resolve::Resolve, { pub fn new(resolve: R) -> Self { Resolve(resolve) } } impl resolve::Resolve for Resolve where R: resolve::Resolve, { type Endpoint = Endpoint; type Resolution = Resolution; fn resolve(&self, dst: &DstAddr) -> Self::Resolution { match dst.as_ref() { Addr::Name(ref name) => Resolution::Name(name.clone(), self.0.resolve(&name)), Addr::Socket(ref addr) => Resolution::Addr(Some(*addr)), } } } // === impl Resolution === impl resolve::Resolution for Resolution where R: resolve::Resolution, { type Endpoint = Endpoint; type Error = R::Error; fn poll(&mut self) -> Poll, Self::Error> { match self { Resolution::Name(ref name, ref mut res) => match try_ready!(res.poll()) { resolve::Update::Remove(addr) => { Ok(Async::Ready(resolve::Update::Remove(addr))) } resolve::Update::Add(addr, metadata) => { // If the endpoint does not have TLS, note the reason. // Otherwise, indicate that we don't (yet) have a TLS // config. This value may be changed by a stack layer that // provides TLS configuration. let tls = match metadata.tls_identity() { Conditional::None(reason) => reason.into(), Conditional::Some(_) => tls::ReasonForNoTls::NoConfig, }; let ep = Endpoint { dst_name: Some(name.clone()), connect: connect::Target::new(addr, Conditional::None(tls)), metadata, }; Ok(Async::Ready(resolve::Update::Add(addr, ep))) } }, Resolution::Addr(ref mut addr) => match addr.take() { Some(addr) => { let tls = tls::ReasonForNoIdentity::NoAuthorityInHttpRequest; let ep = Endpoint { dst_name: None, connect: connect::Target::new(addr, Conditional::None(tls.into())), metadata: Metadata::none(tls), }; Ok(Async::Ready(resolve::Update::Add(addr, ep))) } None => Ok(Async::NotReady), }, } } } } pub mod orig_proto_upgrade { use http; use super::Endpoint; use proxy::http::orig_proto; use svc; #[derive(Debug, Clone)] pub struct Layer; #[derive(Clone, Debug)] pub struct Stack where M: svc::Stack, { inner: M, } pub fn layer() -> Layer { Layer } impl svc::Layer for Layer where M: svc::Stack, M::Value: svc::Service, Response = http::Response>, { type Value = as svc::Stack>::Value; type Error = as svc::Stack>::Error; type Stack = Stack; fn bind(&self, inner: M) -> Self::Stack { Stack { inner } } } // === impl Stack === impl svc::Stack for Stack where M: svc::Stack, M::Value: svc::Service, Response = http::Response>, { type Value = svc::Either, M::Value>; type Error = M::Error; fn make(&self, endpoint: &Endpoint) -> Result { if endpoint.can_use_orig_proto() { self.inner.make(&endpoint).map(|i| svc::Either::A(i.into())) } else { self.inner.make(&endpoint).map(svc::Either::B) } } } }