Add both rustls and openssl client tls implementation
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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?;
|
||||
|
||||
@@ -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
@@ -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"]
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
Reference in New Issue
Block a user