Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade to Hyper 1.0 & Axum 0.7 #1670

Merged
merged 31 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
20369f5
Upgrade to hyper 1 and http 1
alexrudy May 27, 2024
aaede1e
Convert from hyper::Body to http_body::BoxedBody
alexrudy May 27, 2024
ac2698d
Convert tonic::codec::decode to use http >= 1 body types
alexrudy May 27, 2024
3ef308c
Convert tonic::transport::channel to use http >= 1 body types
alexrudy May 27, 2024
8a24c79
[tests] Convert tonic::codec::prost::tests to use http >= 1 body types
alexrudy May 27, 2024
e0f0f6c
Convert tonic::codec::encode to use http >= 1 body types
alexrudy May 27, 2024
51cf7dc
[tests] Convert tonic::service::interceptor::tests to use http >= 1 b…
alexrudy May 27, 2024
4bf003b
Convert tonic::transport to use http >= 1 body types
alexrudy May 27, 2024
70abf84
Convert tonic::transport::server::recover_error to use http >= 1 body…
alexrudy May 27, 2024
c5d0d13
Convert h2c examples to use http >= 1 body types
alexrudy May 27, 2024
c3ce3b3
[tests] Convert MergeTrailers body wrapper in interop server
alexrudy May 27, 2024
f2f7870
[tests] Convert compression tests to use hyper 1 body types
alexrudy May 27, 2024
829eb3b
[tests] Convert complex_tower_middleware Body for hyper 1
alexrudy May 27, 2024
55f9edb
[tests] Convert integration_tests::origin to use http >= 1 body types
alexrudy May 27, 2024
26e640e
Convert tonic-web to use http >= 1 body types
alexrudy May 27, 2024
0e903cb
Adapt for hyper-specific IO traits
alexrudy May 27, 2024
e1e1ffe
Upgrade axum to 0.7
alexrudy May 27, 2024
7a5d95c
Convert service connector for hyper-1.0
alexrudy May 27, 2024
ef542bc
Convert hyper::Client to hyper_util::legacy::Client
alexrudy May 27, 2024
9c6b63a
Identify and propogate connect errors
alexrudy May 27, 2024
39e9d57
Remove hyper::server::conn::AddrStream
alexrudy May 27, 2024
ca9a859
[examples] In h2c, replace hyper::Server with an accept loop
alexrudy May 27, 2024
32c9183
Upgrade tls dependencies
alexrudy May 27, 2024
ed74e45
Combine trailers when streaming decode body
alexrudy May 31, 2024
855ec61
Tweak imports in transport example
alexrudy May 31, 2024
bd9de54
Remove commented out code from examples/h2c
alexrudy Jun 12, 2024
deab62b
tonic-web: avoid copy to vector to base64 encode
alexrudy Jun 12, 2024
39f9f11
tonic-web: Merge subsequent trailer frames
alexrudy Jun 12, 2024
791b138
Comment in tonic::status::find_status_in_source_chain
alexrudy Jun 12, 2024
8345dfe
Make TowerToHyperService crate-private
alexrudy Jun 12, 2024
68a5bbd
Fixup imports in tonic::transport
alexrudy Jun 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 16 additions & 13 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -271,21 +271,21 @@ routeguide = ["dep:async-stream", "tokio-stream", "dep:rand", "dep:serde", "dep:
reflection = ["dep:tonic-reflection"]
autoreload = ["tokio-stream/net", "dep:listenfd"]
health = ["dep:tonic-health"]
grpc-web = ["dep:tonic-web", "dep:bytes", "dep:http", "dep:hyper", "dep:tracing-subscriber", "dep:tower"]
grpc-web = ["dep:tonic-web", "dep:bytes", "dep:http", "dep:hyper", "dep:hyper-util", "dep:tracing-subscriber", "dep:tower"]
tracing = ["dep:tracing", "dep:tracing-subscriber"]
uds = ["tokio-stream/net", "dep:tower", "dep:hyper"]
uds = ["tokio-stream/net", "dep:tower", "dep:hyper", "dep:hyper-util"]
streaming = ["tokio-stream", "dep:h2"]
mock = ["tokio-stream", "dep:tower"]
tower = ["dep:hyper", "dep:tower", "dep:http"]
mock = ["tokio-stream", "dep:tower", "dep:hyper-util"]
tower = ["dep:hyper", "dep:hyper-util", "dep:tower", "dep:http"]
json-codec = ["dep:serde", "dep:serde_json", "dep:bytes"]
compression = ["tonic/gzip"]
tls = ["tonic/tls"]
tls-rustls = ["dep:hyper", "dep:hyper-rustls", "dep:tower", "tower-http/util", "tower-http/add-extension", "dep:rustls-pemfile", "dep:tokio-rustls"]
tls-rustls = ["dep:hyper", "dep:hyper-util", "dep:hyper-rustls", "dep:tower", "tower-http/util", "tower-http/add-extension", "dep:rustls-pemfile", "dep:tokio-rustls", "dep:pin-project", "dep:http-body-util"]
dynamic-load-balance = ["dep:tower"]
timeout = ["tokio/time", "dep:tower"]
tls-client-auth = ["tonic/tls"]
types = ["dep:tonic-types"]
h2c = ["dep:hyper", "dep:tower", "dep:http"]
h2c = ["dep:hyper", "dep:tower", "dep:http", "dep:hyper-util"]
cancellation = ["dep:tokio-util"]

full = ["gcp", "routeguide", "reflection", "autoreload", "health", "grpc-web", "tracing", "uds", "streaming", "mock", "tower", "json-codec", "compression", "tls", "tls-rustls", "dynamic-load-balance", "timeout", "tls-client-auth", "types", "cancellation", "h2c"]
Expand All @@ -311,16 +311,19 @@ serde_json = { version = "1.0", optional = true }
tracing = { version = "0.1.16", optional = true }
tracing-subscriber = { version = "0.3", features = ["tracing-log", "fmt"], optional = true }
prost-types = { version = "0.12", optional = true }
http = { version = "0.2", optional = true }
http-body = { version = "0.4.2", optional = true }
hyper = { version = "0.14", optional = true }
http = { version = "1", optional = true }
http-body = { version = "1", optional = true }
http-body-util = { version = "0.1", optional = true }
hyper = { version = "1", optional = true }
hyper-util = { version = ">=0.1.4, <0.2", optional = true }
listenfd = { version = "1.0", optional = true }
bytes = { version = "1", optional = true }
h2 = { version = "0.3", optional = true }
tokio-rustls = { version = "0.24.0", optional = true }
hyper-rustls = { version = "0.24.0", features = ["http2"], optional = true }
rustls-pemfile = { version = "1", optional = true }
tower-http = { version = "0.4", optional = true }
tokio-rustls = { version = "0.26", optional = true, features = ["ring", "tls12"], default-features = false }
hyper-rustls = { version = "0.27.0", features = ["http2", "ring", "tls12"], optional = true, default-features = false }
rustls-pemfile = { version = "2.0.0", optional = true }
tower-http = { version = "0.5", optional = true }
pin-project = { version = "1.0.11", optional = true }

[build-dependencies]
tonic-build = { path = "../tonic-build", features = ["prost"] }
3 changes: 2 additions & 1 deletion examples/src/grpc-web/client.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use hello_world::{greeter_client::GreeterClient, HelloRequest};
use hyper_util::rt::TokioExecutor;
use tonic_web::GrpcWebClientLayer;

pub mod hello_world {
Expand All @@ -8,7 +9,7 @@ pub mod hello_world {
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Must use hyper directly...
let client = hyper::Client::builder().build_http();
let client = hyper_util::client::legacy::Client::builder(TokioExecutor::new()).build_http();

let svc = tower::ServiceBuilder::new()
.layer(GrpcWebClientLayer::new())
Expand Down
29 changes: 17 additions & 12 deletions examples/src/h2c/client.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use hello_world::greeter_client::GreeterClient;
use hello_world::HelloRequest;
use http::Uri;
use hyper::Client;
use hyper_util::client::legacy::Client;
use hyper_util::rt::TokioExecutor;

pub mod hello_world {
tonic::include_proto!("helloworld");
Expand All @@ -11,7 +12,7 @@ pub mod hello_world {
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let origin = Uri::from_static("http://[::1]:50051");
let h2c_client = h2c::H2cChannel {
client: Client::new(),
client: Client::builder(TokioExecutor::new()).build_http(),
};

let mut client = GreeterClient::with_origin(h2c_client, origin);
Expand All @@ -33,16 +34,20 @@ mod h2c {
task::{Context, Poll},
};

use hyper::{client::HttpConnector, Client};
use tonic::body::BoxBody;
use hyper::body::Incoming;
use hyper_util::{
client::legacy::{connect::HttpConnector, Client},
rt::TokioExecutor,
};
use tonic::body::{empty_body, BoxBody};
use tower::Service;

pub struct H2cChannel {
pub client: Client<HttpConnector>,
pub client: Client<HttpConnector, BoxBody>,
}

impl Service<http::Request<BoxBody>> for H2cChannel {
type Response = http::Response<hyper::Body>;
type Response = http::Response<Incoming>;
type Error = hyper::Error;
type Future =
Pin<Box<dyn std::future::Future<Output = Result<Self::Response, Self::Error>> + Send>>;
Expand All @@ -60,7 +65,7 @@ mod h2c {
let h2c_req = hyper::Request::builder()
.uri(origin)
.header(http::header::UPGRADE, "h2c")
.body(hyper::Body::empty())
.body(empty_body())
.unwrap();

let res = client.request(h2c_req).await.unwrap();
Expand All @@ -72,11 +77,11 @@ mod h2c {
let upgraded_io = hyper::upgrade::on(res).await.unwrap();

// In an ideal world you would somehow cache this connection
let (mut h2_client, conn) = hyper::client::conn::Builder::new()
.http2_only(true)
.handshake(upgraded_io)
.await
.unwrap();
let (mut h2_client, conn) =
hyper::client::conn::http2::Builder::new(TokioExecutor::new())
.handshake(upgraded_io)
.await
.unwrap();
tokio::spawn(conn);

h2_client.send_request(request).await
Expand Down
54 changes: 36 additions & 18 deletions examples/src/h2c/server.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
use std::net::SocketAddr;

use hyper_util::rt::{TokioExecutor, TokioIo};
use hyper_util::server::conn::auto::Builder;
use hyper_util::service::TowerToHyperService;
use tokio::net::TcpListener;
use tonic::{transport::Server, Request, Response, Status};

use hello_world::greeter_server::{Greeter, GreeterServer};
use hello_world::{HelloReply, HelloRequest};
use tower::make::Shared;

pub mod hello_world {
tonic::include_proto!("helloworld");
Expand All @@ -28,28 +33,45 @@ impl Greeter for MyGreeter {

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:50051".parse().unwrap();
let addr: SocketAddr = "[::1]:50051".parse().unwrap();
let greeter = MyGreeter::default();

println!("GreeterServer listening on {}", addr);

let incoming = TcpListener::bind(addr).await?;
let svc = Server::builder()
.add_service(GreeterServer::new(greeter))
.into_router();

let h2c = h2c::H2c { s: svc };

let server = hyper::Server::bind(&addr).serve(Shared::new(h2c));
server.await.unwrap();

Ok(())
loop {
match incoming.accept().await {
Ok((io, _)) => {
let router = h2c.clone();
tokio::spawn(async move {
let builder = Builder::new(TokioExecutor::new());
let conn = builder.serve_connection_with_upgrades(
TokioIo::new(io),
TowerToHyperService::new(router),
);
let _ = conn.await;
});
}
Err(e) => {
eprintln!("Error accepting connection: {}", e);
}
}
}
}

mod h2c {
use std::pin::Pin;

use http::{Request, Response};
use hyper::Body;
use hyper::body::Incoming;
use hyper_util::{rt::TokioExecutor, service::TowerToHyperService};
use tonic::{body::empty_body, transport::AxumBoxBody};
use tower::Service;

#[derive(Clone)]
Expand All @@ -59,17 +81,14 @@ mod h2c {

type BoxError = Box<dyn std::error::Error + Send + Sync>;

impl<S> Service<Request<Body>> for H2c<S>
impl<S> Service<Request<Incoming>> for H2c<S>
where
S: Service<Request<Body>, Response = Response<tonic::transport::AxumBoxBody>>
+ Clone
+ Send
+ 'static,
S: Service<Request<Incoming>, Response = Response<AxumBoxBody>> + Clone + Send + 'static,
S::Future: Send + 'static,
S::Error: Into<BoxError> + Sync + Send + 'static,
S::Response: Send + 'static,
{
type Response = hyper::Response<Body>;
type Response = hyper::Response<tonic::body::BoxBody>;
type Error = hyper::Error;
type Future =
Pin<Box<dyn std::future::Future<Output = Result<Self::Response, Self::Error>> + Send>>;
Expand All @@ -81,20 +100,19 @@ mod h2c {
std::task::Poll::Ready(Ok(()))
}

fn call(&mut self, mut req: hyper::Request<Body>) -> Self::Future {
fn call(&mut self, mut req: hyper::Request<Incoming>) -> Self::Future {
let svc = self.s.clone();
Box::pin(async move {
tokio::spawn(async move {
let upgraded_io = hyper::upgrade::on(&mut req).await.unwrap();

hyper::server::conn::Http::new()
.http2_only(true)
.serve_connection(upgraded_io, svc)
hyper::server::conn::http2::Builder::new(TokioExecutor::new())
.serve_connection(upgraded_io, TowerToHyperService::new(svc))
.await
.unwrap();
});

let mut res = hyper::Response::new(hyper::Body::empty());
let mut res = hyper::Response::new(empty_body());
*res.status_mut() = http::StatusCode::SWITCHING_PROTOCOLS;
res.headers_mut().insert(
hyper::header::UPGRADE,
Expand Down
1 change: 1 addition & 0 deletions examples/src/interceptor/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ fn intercept(mut req: Request<()>) -> Result<Request<()>, Status> {
Ok(req)
}

#[derive(Clone)]
struct MyExtension {
some_piece_of_data: String,
}
3 changes: 2 additions & 1 deletion examples/src/mock/mock.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use hyper_util::rt::TokioIo;
use tonic::{
transport::{Endpoint, Server, Uri},
Request, Response, Status,
Expand Down Expand Up @@ -36,7 +37,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {

async move {
if let Some(client) = client {
Ok(client)
Ok(TokioIo::new(client))
} else {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
Expand Down
10 changes: 5 additions & 5 deletions examples/src/tls_rustls/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ pub mod pb {
tonic::include_proto!("/grpc.examples.unaryecho");
}

use hyper::{client::HttpConnector, Uri};
use hyper::Uri;
use hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor};
use pb::{echo_client::EchoClient, EchoRequest};
use tokio_rustls::rustls::{ClientConfig, RootCertStore};

Expand All @@ -17,11 +18,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut roots = RootCertStore::empty();

let mut buf = std::io::BufReader::new(&fd);
let certs = rustls_pemfile::certs(&mut buf)?;
roots.add_parsable_certificates(&certs);
let certs = rustls_pemfile::certs(&mut buf).collect::<Result<Vec<_>, _>>()?;
roots.add_parsable_certificates(certs.into_iter());

let tls = ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(roots)
.with_no_client_auth();

Expand All @@ -47,7 +47,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.map_request(|_| Uri::from_static("https://[::1]:50051"))
.service(http);

let client = hyper::Client::builder().build(connector);
let client = hyper_util::client::legacy::Client::builder(TokioExecutor::new()).build(connector);

// Using `with_origin` will let the codegenerated client set the `scheme` and
// `authority` from the porvided `Uri`.
Expand Down
Loading