216 lines
6.3 KiB
Rust
216 lines
6.3 KiB
Rust
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<NameAddr>,
|
|
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<tls::ConditionalClientConfig> 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<Endpoint> 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: resolve::Resolve<NameAddr>>(R);
|
|
|
|
#[derive(Debug)]
|
|
pub enum Resolution<R: resolve::Resolution> {
|
|
Name(NameAddr, R),
|
|
Addr(Option<SocketAddr>),
|
|
}
|
|
|
|
// === impl Resolve ===
|
|
|
|
impl<R> Resolve<R>
|
|
where
|
|
R: resolve::Resolve<NameAddr, Endpoint = Metadata>,
|
|
{
|
|
pub fn new(resolve: R) -> Self {
|
|
Resolve(resolve)
|
|
}
|
|
}
|
|
|
|
impl<R> resolve::Resolve<DstAddr> for Resolve<R>
|
|
where
|
|
R: resolve::Resolve<NameAddr, Endpoint = Metadata>,
|
|
{
|
|
type Endpoint = Endpoint;
|
|
type Resolution = Resolution<R::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<R> resolve::Resolution for Resolution<R>
|
|
where
|
|
R: resolve::Resolution<Endpoint = Metadata>,
|
|
{
|
|
type Endpoint = Endpoint;
|
|
type Error = R::Error;
|
|
|
|
fn poll(&mut self) -> Poll<resolve::Update<Self::Endpoint>, 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<M>
|
|
where
|
|
M: svc::Stack<Endpoint>,
|
|
{
|
|
inner: M,
|
|
}
|
|
|
|
pub fn layer() -> Layer {
|
|
Layer
|
|
}
|
|
|
|
impl<M, A, B> svc::Layer<Endpoint, Endpoint, M> for Layer
|
|
where
|
|
M: svc::Stack<Endpoint>,
|
|
M::Value: svc::Service<Request = http::Request<A>, Response = http::Response<B>>,
|
|
{
|
|
type Value = <Stack<M> as svc::Stack<Endpoint>>::Value;
|
|
type Error = <Stack<M> as svc::Stack<Endpoint>>::Error;
|
|
type Stack = Stack<M>;
|
|
|
|
fn bind(&self, inner: M) -> Self::Stack {
|
|
Stack { inner }
|
|
}
|
|
}
|
|
|
|
// === impl Stack ===
|
|
|
|
impl<M, A, B> svc::Stack<Endpoint> for Stack<M>
|
|
where
|
|
M: svc::Stack<Endpoint>,
|
|
M::Value: svc::Service<Request = http::Request<A>, Response = http::Response<B>>,
|
|
{
|
|
type Value = svc::Either<orig_proto::Upgrade<M::Value>, M::Value>;
|
|
type Error = M::Error;
|
|
|
|
fn make(&self, endpoint: &Endpoint) -> Result<Self::Value, Self::Error> {
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
}
|