Add both rustls and openssl client tls implementation

This commit is contained in:
Lucio Franco
2019-09-01 01:37:19 -04:00
parent d43b2a3c63
commit cc2fa986a6
9 changed files with 128 additions and 62 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ pub mod hello_world {
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let origin = http::Uri::from_static("http://[::1]:50051");
let svc = Client::connect(origin)?;
let svc = Client::builder().build(origin)?;
let mut client = hello_world::GreeterClient::new(svc);
+1 -1
View File
@@ -13,7 +13,7 @@ mod route_guide {
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let origin = http::Uri::from_static("http://[::1]:10000");
let svc = Client::connect(origin)?;
let svc = Client::builder().build(origin)?;
let mut client = route_guide::RouteGuideClient::new(svc);
let start = Instant::now();
+2 -2
View File
@@ -22,8 +22,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let test_cases = matches.test_case;
let addr = "localhost:8080";
let origin = http::Uri::from_shared(format!("https://{}", addr).into()).unwrap();
let addr = "localhost:10000";
let origin = http::Uri::from_shared(format!("http://{}", addr).into()).unwrap();
let mut client = client::create(origin.clone()).await?;
let mut unimplemented_client = client::create_unimplemented(origin).await?;
+12 -2
View File
@@ -22,7 +22,12 @@ const SPECIAL_TEST_STATUS_MESSAGE: &'static str =
"\t\ntest with whitespace\r\nand Unicode BMP ☺ and non-BMP 😈\t\n";
pub async fn create(origin: http::Uri) -> Result<TestClient, Box<dyn std::error::Error>> {
let svc = Client::connect_with_tls(origin, "tonic-interop/data/ca.pem").await?;
let ca = tokio::fs::read("tonic-interop/data/ca.pem").await?;
let svc = Client::builder()
.tls(ca)
.tls_override_domain("foo.test.google.fr")
.build(origin)?;
Ok(TestServiceClient::new(svc))
}
@@ -30,7 +35,12 @@ pub async fn create(origin: http::Uri) -> Result<TestClient, Box<dyn std::error:
pub async fn create_unimplemented(
origin: http::Uri,
) -> Result<UnimplementedClient, Box<dyn std::error::Error>> {
let svc = Client::connect(origin)?;
let ca = tokio::fs::read("tonic-interop/data/ca.pem").await?;
let svc = Client::builder()
.tls(ca)
.tls_override_domain("foo.test.google.fr")
.build(origin)?;
Ok(UnimplementedServiceClient::new(svc))
}
+10 -4
View File
@@ -26,12 +26,16 @@ pin-project = "0.4.0-alpha.2"
hyper = { git = "https://github.com/hyperium/hyper", optional = true}
tokio = { version = "=0.2.0-alpha.4", default-features = false, features = ["tcp"], optional = true }
tower-make = "=0.1.0-alpha.2"
tokio-rustls = { path = "../../tokio-rustls", optional = true }
tokio-openssl = "=0.4.0-alpha.4"
openssl = "*"
tower-reconnect = { path = "../../tower/tower-reconnect", optional = true }
tower-buffer = { path = "../../tower/tower-buffer", optional = true }
# openssl
tokio-openssl = { version = "=0.4.0-alpha.4", optional = true }
openssl = { version = "0.10", optional = true }
# rustls
tokio-rustls = { path = "../../tokio-rustls", optional = true }
[features]
default = ["transport"]
transport = [
@@ -39,5 +43,7 @@ transport = [
"tower-reconnect",
"tower-buffer",
"tokio",
"tokio-rustls",
"openssl-1",
]
openssl-1 = ["openssl", "tokio-openssl"]
rustls = ["tokio-rustls"]
+85 -31
View File
@@ -1,16 +1,14 @@
use super::tls::TlsConnector;
use crate::{
body::BoxBody,
service::{AddOrigin, BoxService, GrpcService},
};
use futures_util::try_future::{MapErr, TryFutureExt};
use http::Uri;
use hyper::client::conn::Builder;
use hyper::client::conn;
use hyper::client::connect::HttpConnector;
use hyper::client::service::Connect;
use hyper::{Request, Response};
use std::future::Future;
use std::path::Path;
use std::pin::Pin;
use std::task::{Context, Poll};
use tower_buffer::{future::ResponseFuture, Buffer};
@@ -33,34 +31,8 @@ pub struct Client {
}
impl Client {
pub fn connect(addr: Uri) -> Result<Self, super::Error> {
let settings = Builder::new().http2_only(true).clone();
let maker = Connect::new(HttpConnector::new(), settings);
let svc = tower_reconnect::Reconnect::new(maker, addr.clone());
let svc = AddOrigin::new(svc, addr);
let svc = BoxService::new(svc);
let svc = Buffer::new(Box::new(svc) as Inner, 100);
Ok(Self { svc })
}
pub async fn connect_with_tls<P: AsRef<Path>>(addr: Uri, ca: P) -> Result<Self, super::Error> {
let settings = Builder::new().http2_only(true).clone();
// let tls_connector = TlsConnector::load(ca).await?;
let tls_connector = super::openssl::TlsConnector::load(ca).await?;
let maker = Connect::new(tls_connector, settings);
let svc = tower_reconnect::Reconnect::new(maker, addr.clone());
let svc = AddOrigin::new(svc, addr);
let svc = BoxService::new(svc);
let svc = Buffer::new(Box::new(svc) as Inner, 100);
Ok(Self { svc })
pub fn builder() -> Builder {
Builder::new()
}
}
@@ -83,3 +55,85 @@ impl GrpcService<BoxBody> for Client {
.map_err(|e| super::Error::from((super::ErrorKind::Client, e)))
}
}
#[derive(Debug)]
pub struct Builder {
ca: Option<Vec<u8>>,
override_domain: Option<String>,
buffer_size: usize,
}
impl Builder {
fn new() -> Self {
Self {
ca: None,
override_domain: None,
buffer_size: 1024,
}
}
#[cfg(any(feature = "openssl-1", feature = "rustls"))]
pub fn tls(&mut self, ca: Vec<u8>) -> &mut Self {
self.ca = Some(ca);
self
}
#[cfg(any(feature = "openssl-1", feature = "rustls"))]
pub fn tls_override_domain<D: AsRef<str>>(&mut self, domain: D) -> &mut Self {
self.override_domain = Some(domain.as_ref().into());
self
}
pub fn buffer(&mut self, size: usize) -> &mut Self {
self.buffer_size = size;
self
}
pub fn build<T>(&self, uri: T) -> Result<Client, super::Error>
where
Uri: http::HttpTryFrom<T>,
{
let uri: Uri = match http::HttpTryFrom::try_from(uri) {
Ok(u) => u,
Err(e) => panic!("Invalid uri: {}", e.into()),
};
let settings = conn::Builder::new().http2_only(true).clone();
let svc = if let Some(ca) = &self.ca {
let domain = self
.override_domain
.clone()
.unwrap_or_else(|| uri.to_string());
#[cfg(not(any(feature = "openssl-1", feature = "rustls")))]
panic!("tls configured when no tls implementation feature was selected!");
#[cfg(feature = "openssl-1")]
let connector = super::openssl::TlsConnector::new(ca.clone(), domain)?;
#[cfg(feature = "rustls")]
#[cfg(not(feature = "openssl-1"))]
let connector = super::openssl::TlsConnector::new(ca.clone(), domain)?;
let maker = Connect::new(connector, settings);
let svc = tower_reconnect::Reconnect::new(maker, uri.clone());
let svc = AddOrigin::new(svc, uri);
let svc = BoxService::new(svc);
Buffer::new(Box::new(svc) as Inner, 100)
} else {
let connector = HttpConnector::new();
let maker = Connect::new(connector, settings);
let svc = tower_reconnect::Reconnect::new(maker, uri.clone());
let svc = AddOrigin::new(svc, uri);
let svc = BoxService::new(svc);
Buffer::new(Box::new(svc) as Inner, 100)
};
// let connector = super::rustls::TlsConnector::load(ca).await?;
// let connector = super::openssl::TlsConnector::load(ca).await?;
Ok(Client { svc })
}
}
+4 -2
View File
@@ -1,6 +1,8 @@
mod client;
#[cfg(feature = "openssl-1")]
mod openssl;
mod tls;
#[cfg(feature = "rustls")]
mod rustls;
pub use self::client::Client;
@@ -14,7 +16,7 @@ pub struct Error {
#[derive(Debug)]
pub(crate) enum ErrorKind {
Client,
UnableToNegotiateH2, // Server,
// Server,
}
impl From<ErrorKind> for Error {
+11 -10
View File
@@ -1,33 +1,33 @@
use http::Uri;
use hyper::client::connect::HttpConnector;
use openssl::ssl::{ConnectConfiguration, SslConnector, SslMethod};
use openssl::ssl::{SslConnector, SslMethod};
use openssl::x509::X509;
use std::{
future::Future,
path::Path,
pin::Pin,
sync::Arc,
task::{Context, Poll},
};
use tokio::{fs, net::TcpStream};
use tokio::net::TcpStream;
use tokio_openssl::{connect, SslStream};
use tower_make::MakeConnection;
use tower_service::Service;
const ALPN_H2: &str = "h2";
#[derive(Clone)]
pub struct TlsConnector {
http: HttpConnector,
config: SslConnector,
domain: String,
}
impl TlsConnector {
pub async fn load<P: AsRef<Path>>(ca: P) -> Result<Self, super::Error> {
pub fn new(ca: Vec<u8>, domain: String) -> Result<Self, super::Error> {
let mut config = SslConnector::builder(SslMethod::tls()).unwrap();
config.set_alpn_protos(ALPN_H2.as_bytes()).unwrap();
config.set_alpn_protos(b"\x02h2").unwrap();
config.set_ca_file(ca).unwrap();
let ca = X509::from_pem(&ca[..]).unwrap();
config.cert_store_mut().add_cert(ca).unwrap();
let config = config.build();
@@ -37,6 +37,7 @@ impl TlsConnector {
Ok(Self {
http,
config,
domain,
})
}
}
@@ -56,10 +57,10 @@ impl Service<Uri> for TlsConnector {
fn call(&mut self, uri: Uri) -> Self::Future {
let config = self.config.configure().unwrap();
let tcp = self.http.make_connection(uri.clone());
let domain = self.domain.clone();
let fut = async move {
let io = tcp.await.unwrap();
let domain = "foo.test.google.fr";
let tls = connect(config, &domain, io).await.unwrap();
Ok(tls)
};
@@ -17,7 +17,7 @@ use tokio_rustls::{
use tower_make::MakeConnection;
use tower_service::Service;
const ALPN_H2: &str = "h2";
const ALPN_H2: &str = "\x02h2";
#[derive(Clone)]
pub struct TlsConnector {
@@ -26,14 +26,7 @@ pub struct TlsConnector {
}
impl TlsConnector {
pub async fn load<P: AsRef<Path>>(ca: P) -> Result<Self, super::Error> {
let pem = fs::read(ca)
.await
.map_err(|e| super::Error::from((super::ErrorKind::Client, e.into())))?;
Ok(TlsConnector::new(pem))
}
fn new(ca: Vec<u8>) -> Self {
pub fn new(ca: Vec<u8>, domain: String) -> Self {
let mut buf = std::io::Cursor::new(ca);
let mut config = ClientConfig::new();