5
5
//! with a [tower] service that performs the translation between protocols and handles `cors`
6
6
//! requests.
7
7
//!
8
- //! ## Getting Started
9
- //!
10
- //! ```toml
11
- //! [dependencies]
12
- //! tonic_web = "0.1"
13
- //! ```
14
- //!
15
8
//! ## Enabling tonic services
16
9
//!
17
10
//! The easiest way to get started, is to call the [`enable`] function with your tonic service
31
24
//!
32
25
//! Ok(())
33
26
//! }
34
- //!
35
27
//! ```
36
28
//! This will apply a default configuration that works well with grpc-web clients out of the box.
37
29
//!
38
30
//! You can customize the CORS configuration composing the [`GrpcWebLayer`] with the cors layer of your choice.
39
31
//!
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
+ //!
40
50
//! Alternatively, if you have a tls enabled server, you could skip setting `accept_http1` to `true`.
41
51
//! This works because the browser will handle `ALPN`.
42
52
//!
@@ -96,8 +106,8 @@ mod service;
96
106
97
107
use http:: header:: HeaderName ;
98
108
use 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 } ;
101
111
use tower_layer:: Layer ;
102
112
use tower_service:: Service ;
103
113
@@ -112,14 +122,14 @@ type BoxError = Box<dyn std::error::Error + Send + Sync>;
112
122
/// Enable a tonic service to handle grpc-web requests with the default configuration.
113
123
///
114
124
/// 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 >
116
126
where
117
127
S : Service < http:: Request < hyper:: Body > , Response = http:: Response < BoxBody > > ,
118
128
S : Clone + Send + ' static ,
119
129
S :: Future : Send + ' static ,
120
130
S :: Error : Into < BoxError > + Send ,
121
131
{
122
- CorsLayer :: new ( )
132
+ let cors = CorsLayer :: new ( )
123
133
. allow_origin ( AllowOrigin :: mirror_request ( ) )
124
134
. allow_credentials ( true )
125
135
. max_age ( DEFAULT_MAX_AGE )
@@ -136,8 +146,45 @@ where
136
146
. cloned ( )
137
147
. map ( HeaderName :: from_static)
138
148
. 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 ;
141
188
}
142
189
143
190
pub ( crate ) mod util {
0 commit comments