1 use bytes::{Buf, BufMut, Bytes, BytesMut}; 2 use hello_world::{HelloReply, HelloRequest}; 3 use http::header::{ACCEPT, CONTENT_TYPE}; 4 5 pub mod hello_world { 6 tonic::include_proto!("helloworld"); 7 } 8 9 #[tokio::main] 10 async fn main() -> Result<(), Box<dyn std::error::Error>> { 11 let msg = HelloRequest { 12 name: "Bob".to_string(), 13 }; 14 15 // a good old http/1.1 request 16 let request = http::Request::builder() 17 .version(http::Version::HTTP_11) 18 .method(http::Method::POST) 19 .uri("http://127.0.0.1:3000/helloworld.Greeter/SayHello") 20 .header(CONTENT_TYPE, "application/grpc-web") 21 .header(ACCEPT, "application/grpc-web") 22 .body(hyper::Body::from(encode_body(msg))) 23 .unwrap(); 24 25 let client = hyper::Client::new(); 26 27 let response = client.request(request).await.unwrap(); 28 29 assert_eq!( 30 response.headers().get(CONTENT_TYPE).unwrap(), 31 "application/grpc-web+proto" 32 ); 33 34 let body = response.into_body(); 35 let reply = decode_body::<HelloReply>(body).await; 36 37 println!("REPLY={:?}", reply); 38 39 Ok(()) 40 } 41 42 // one byte for the compression flag plus four bytes for the length 43 const GRPC_HEADER_SIZE: usize = 5; 44 45 fn encode_body<T>(msg: T) -> Bytes 46 where 47 T: prost::Message, 48 { 49 let mut buf = BytesMut::with_capacity(1024); 50 51 // first skip past the header 52 // cannot write it yet since we don't know the size of the 53 // encoded message 54 buf.reserve(GRPC_HEADER_SIZE); 55 unsafe { 56 buf.advance_mut(GRPC_HEADER_SIZE); 57 } 58 59 // write the message 60 msg.encode(&mut buf).unwrap(); 61 62 // now we know the size of encoded message and can write the 63 // header 64 let len = buf.len() - GRPC_HEADER_SIZE; 65 { 66 let mut buf = &mut buf[..GRPC_HEADER_SIZE]; 67 68 // compression flag, 0 means "no compression" 69 buf.put_u8(0); 70 71 buf.put_u32(len as u32); 72 } 73 74 buf.split_to(len + GRPC_HEADER_SIZE).freeze() 75 } 76 77 async fn decode_body<T>(body: hyper::Body) -> T 78 where 79 T: Default + prost::Message, 80 { 81 let mut body = hyper::body::to_bytes(body).await.unwrap(); 82 83 // ignore the compression flag 84 body.advance(1); 85 86 let len = body.get_u32(); 87 let msg = T::decode(&mut body.split_to(len as usize)).unwrap(); 88 89 msg 90 } 91