55//! with a [tower] service that performs the translation between protocols and handles `cors`
66//! requests.
77//!
8- //! ## Getting Started
9- //!
10- //! ```toml
11- //! [dependencies]
12- //! tonic_web = "0.1"
13- //! ```
14- //!
158//! ## Enabling tonic services
169//!
1710//! The easiest way to get started, is to call the [`enable`] function with your tonic service
3124//!
3225//! Ok(())
3326//! }
34- //!
3527//! ```
3628//! This will apply a default configuration that works well with grpc-web clients out of the box.
3729//!
3830//! You can customize the CORS configuration composing the [`GrpcWebLayer`] with the cors layer of your choice.
3931//!
32+ //! ```ignore
33+ //! #[tokio::main]
34+ //! async fn main() -> Result<(), Box<dyn std::error::Error>> {
35+ //! let addr = "[::1]:50051".parse().unwrap();
36+ //! let greeter = GreeterServer::new(MyGreeter::default());
37+ //!
38+ //! Server::builder()
39+ //! .accept_http1(true)
40+ //! // This will apply the gRPC-Web translation layer
41+ //! .layer(GrpcWebLayer::new())
42+ //! .add_service(greeter)
43+ //! .serve(addr)
44+ //! .await?;
45+ //!
46+ //! Ok(())
47+ //! }
48+ //! ```
49+ //!
4050//! Alternatively, if you have a tls enabled server, you could skip setting `accept_http1` to `true`.
4151//! This works because the browser will handle `ALPN`.
4252//!
@@ -96,8 +106,8 @@ mod service;
96106
97107use http:: header:: HeaderName ;
98108use std:: time:: Duration ;
99- use tonic:: body:: BoxBody ;
100- use tower_http:: cors:: { AllowOrigin , Cors , CorsLayer } ;
109+ use tonic:: { body:: BoxBody , server :: NamedService } ;
110+ use tower_http:: cors:: { AllowOrigin , CorsLayer } ;
101111use tower_layer:: Layer ;
102112use tower_service:: Service ;
103113
@@ -112,14 +122,14 @@ type BoxError = Box<dyn std::error::Error + Send + Sync>;
112122/// Enable a tonic service to handle grpc-web requests with the default configuration.
113123///
114124/// You can customize the CORS configuration composing the [`GrpcWebLayer`] with the cors layer of your choice.
115- pub fn enable < S > ( service : S ) -> Cors < GrpcWebService < S > >
125+ pub fn enable < S > ( service : S ) -> CorsGrpcWeb < S >
116126where
117127 S : Service < http:: Request < hyper:: Body > , Response = http:: Response < BoxBody > > ,
118128 S : Clone + Send + ' static ,
119129 S :: Future : Send + ' static ,
120130 S :: Error : Into < BoxError > + Send ,
121131{
122- CorsLayer :: new ( )
132+ let cors = CorsLayer :: new ( )
123133 . allow_origin ( AllowOrigin :: mirror_request ( ) )
124134 . allow_credentials ( true )
125135 . max_age ( DEFAULT_MAX_AGE )
@@ -136,8 +146,45 @@ where
136146 . cloned ( )
137147 . map ( HeaderName :: from_static)
138148 . collect :: < Vec < HeaderName > > ( ) ,
139- )
140- . layer ( GrpcWebService :: new ( service) )
149+ ) ;
150+
151+ tower_layer:: layer_fn ( |s| CorsGrpcWeb ( cors. layer ( s) ) ) . layer ( GrpcWebService :: new ( service) )
152+ }
153+
154+ /// A newtype wrapper around [`GrpcWebLayer`] and [`tower_http::cors::CorsLayer`] to allow
155+ /// `tonic_web::enable` to implement the [`NamedService`] trait.
156+ #[ derive( Debug , Clone ) ]
157+ pub struct CorsGrpcWeb < S > ( tower_http:: cors:: Cors < GrpcWebService < S > > ) ;
158+
159+ impl < S > Service < http:: Request < hyper:: Body > > for CorsGrpcWeb < S >
160+ where
161+ S : Service < http:: Request < hyper:: Body > , Response = http:: Response < BoxBody > > ,
162+ S : Clone + Send + ' static ,
163+ S :: Future : Send + ' static ,
164+ S :: Error : Into < BoxError > + Send ,
165+ {
166+ type Response = S :: Response ;
167+ type Error = S :: Error ;
168+ type Future =
169+ <tower_http:: cors:: Cors < GrpcWebService < S > > as Service < http:: Request < hyper:: Body > > >:: Future ;
170+
171+ fn poll_ready (
172+ & mut self ,
173+ cx : & mut std:: task:: Context < ' _ > ,
174+ ) -> std:: task:: Poll < Result < ( ) , Self :: Error > > {
175+ self . 0 . poll_ready ( cx)
176+ }
177+
178+ fn call ( & mut self , req : http:: Request < hyper:: Body > ) -> Self :: Future {
179+ self . 0 . call ( req)
180+ }
181+ }
182+
183+ impl < S > NamedService for CorsGrpcWeb < S >
184+ where
185+ S : NamedService ,
186+ {
187+ const NAME : & ' static str = S :: NAME ;
141188}
142189
143190pub ( crate ) mod util {
0 commit comments