xref: /tonic/examples/src/h2c/client.rs (revision b29f4668)
1 use hello_world::greeter_client::GreeterClient;
2 use hello_world::HelloRequest;
3 use http::Uri;
4 use hyper::Client;
5 
6 pub mod hello_world {
7     tonic::include_proto!("helloworld");
8 }
9 
10 #[tokio::main]
11 async fn main() -> Result<(), Box<dyn std::error::Error>> {
12     let origin = Uri::from_static("http://[::1]:50051");
13     let h2c_client = h2c::H2cChannel {
14         client: Client::new(),
15     };
16 
17     let mut client = GreeterClient::with_origin(h2c_client, origin);
18 
19     let request = tonic::Request::new(HelloRequest {
20         name: "Tonic".into(),
21     });
22 
23     let response = client.say_hello(request).await?;
24 
25     println!("RESPONSE={:?}", response);
26 
27     Ok(())
28 }
29 
30 mod h2c {
31     use std::{
32         pin::Pin,
33         task::{Context, Poll},
34     };
35 
36     use hyper::{client::HttpConnector, Client};
37     use tonic::body::BoxBody;
38     use tower::Service;
39 
40     pub struct H2cChannel {
41         pub client: Client<HttpConnector>,
42     }
43 
44     impl Service<http::Request<BoxBody>> for H2cChannel {
45         type Response = http::Response<hyper::Body>;
46         type Error = hyper::Error;
47         type Future =
48             Pin<Box<dyn std::future::Future<Output = Result<Self::Response, Self::Error>> + Send>>;
49 
50         fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
51             Poll::Ready(Ok(()))
52         }
53 
54         fn call(&mut self, request: http::Request<BoxBody>) -> Self::Future {
55             let client = self.client.clone();
56 
57             Box::pin(async move {
58                 let origin = request.uri();
59 
60                 let h2c_req = hyper::Request::builder()
61                     .uri(origin)
62                     .header(http::header::UPGRADE, "h2c")
63                     .body(hyper::Body::empty())
64                     .unwrap();
65 
66                 let res = client.request(h2c_req).await.unwrap();
67 
68                 if res.status() != http::StatusCode::SWITCHING_PROTOCOLS {
69                     panic!("Our server didn't upgrade: {}", res.status());
70                 }
71 
72                 let upgraded_io = hyper::upgrade::on(res).await.unwrap();
73 
74                 // In an ideal world you would somehow cache this connection
75                 let (mut h2_client, conn) = hyper::client::conn::Builder::new()
76                     .http2_only(true)
77                     .handshake(upgraded_io)
78                     .await
79                     .unwrap();
80                 tokio::spawn(conn);
81 
82                 h2_client.send_request(request).await
83             })
84         }
85     }
86 }
87