Files
tonic/tonic-interop/src/bin/server.rs
T
James NugentandLucio Franco 8db3961491 feat(transport): Expose more granular control of TLS configuration (#48)
This commit reworks TLS configuration of both servers and endpoints in
order to provide a more flexible API. We now add options to configure
the selected TLS library using the appropriate 'native' configuration
structures, as well as retaining the existing simplier interface which
is compatible with both.

The new API can also be easily extended to support simple interfaces for
configuring mTLS and a range of other options without creating sprawl
in the builders for `Server` and `Endpoint`.
2019-10-08 11:49:05 -04:00

163 lines
4.6 KiB
Rust

use http::header::HeaderName;
use structopt::StructOpt;
use tonic::body::BoxBody;
use tonic::client::GrpcService;
use tonic::transport::{Identity, Server, ServerTlsConfig};
use tonic_interop::{server, MergeTrailers};
#[derive(StructOpt)]
struct Opts {
#[structopt(long)]
use_tls: bool,
}
#[tokio::main]
async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
tonic_interop::trace_init();
let matches = Opts::from_args();
let addr = "127.0.0.1:10000".parse().unwrap();
let mut builder = Server::builder();
if matches.use_tls {
let cert = tokio::fs::read("tonic-interop/data/server1.pem").await?;
let key = tokio::fs::read("tonic-interop/data/server1.key").await?;
let identity = Identity::from_pem(cert, key);
builder.tls_config(ServerTlsConfig::with_openssl().identity(identity));
}
builder.interceptor_fn(|svc, req| {
let echo_header = req
.headers()
.get("x-grpc-test-echo-initial")
.map(Clone::clone);
let echo_trailer = req
.headers()
.get("x-grpc-test-echo-trailing-bin")
.map(Clone::clone)
.map(|v| (HeaderName::from_static("x-grpc-test-echo-trailing-bin"), v));
let call = svc.call(req);
async move {
let mut res = call.await?;
if let Some(echo_header) = echo_header {
res.headers_mut()
.insert("x-grpc-test-echo-initial", echo_header);
}
Ok(res
.map(|b| MergeTrailers::new(b, echo_trailer))
.map(BoxBody::new))
}
});
builder
.serve(
addr,
router::Router {
test_service: std::sync::Arc::new(server::TestService),
unimplemented_service: std::sync::Arc::new(server::UnimplementedService),
},
)
.await?;
Ok(())
}
mod router {
use futures_util::future;
use http::{Request, Response};
use std::sync::Arc;
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
use tonic::{body::BoxBody, transport::Body};
use tonic_interop::server::{
TestService, TestServiceServer, UnimplementedService, UnimplementedServiceServer,
};
use tower::Service;
#[derive(Clone)]
pub struct Router {
pub test_service: Arc<TestService>,
pub unimplemented_service: Arc<UnimplementedService>,
}
impl Service<()> for Router {
type Response = Router;
type Error = Never;
type Future = future::Ready<Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Ok(()).into()
}
fn call(&mut self, _req: ()) -> Self::Future {
future::ok(self.clone())
}
}
impl Service<Request<Body>> for Router {
type Response = Response<BoxBody>;
type Error = Never;
type Future =
Pin<Box<dyn Future<Output = Result<Response<BoxBody>, Never>> + Send + 'static>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Ok(()).into()
}
fn call(&mut self, req: Request<Body>) -> Self::Future {
let mut segments = req.uri().path().split("/");
segments.next();
let service = segments.next().unwrap();
match service {
"grpc.testing.TestService" => {
let me = self.clone();
Box::pin(async move {
let mut svc = TestServiceServer::from_shared(me.test_service);
let mut svc = svc.call(()).await.unwrap();
let res = svc.call(req).await.unwrap();
Ok(res)
})
}
"grpc.testing.UnimplementedService" => {
let me = self.clone();
Box::pin(async move {
let mut svc =
UnimplementedServiceServer::from_shared(me.unimplemented_service);
let mut svc = svc.call(()).await.unwrap();
let res = svc.call(req).await.unwrap();
Ok(res)
})
}
_ => unimplemented!(),
}
}
}
#[derive(Debug)]
pub enum Never {}
impl std::fmt::Display for Never {
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match *self {}
}
}
impl std::error::Error for Never {}
}