@@ -9,16 +9,24 @@ use devtools_wire_format::sources::sources_server::SourcesServer;
99use devtools_wire_format:: tauri:: tauri_server;
1010use devtools_wire_format:: tauri:: tauri_server:: TauriServer ;
1111use futures:: { FutureExt , TryStreamExt } ;
12+ use http:: HeaderValue ;
13+ use hyper:: Body ;
1214use std:: net:: SocketAddr ;
15+ use std:: pin:: Pin ;
16+ use std:: sync:: { Arc , Mutex } ;
17+ use std:: task:: { Context , Poll } ;
1318use tokio:: sync:: mpsc;
19+ use tonic:: body:: BoxBody ;
1420use tonic:: codegen:: http:: Method ;
1521use tonic:: codegen:: tokio_stream:: wrappers:: ReceiverStream ;
1622use tonic:: codegen:: BoxStream ;
1723use tonic:: { Request , Response , Status } ;
1824use tonic_health:: pb:: health_server:: { Health , HealthServer } ;
1925use tonic_health:: server:: HealthReporter ;
2026use tonic_health:: ServingStatus ;
21- use tower_http:: cors:: { AllowHeaders , CorsLayer } ;
27+ use tower:: Service ;
28+ use tower_http:: cors:: { AllowHeaders , AllowOrigin , CorsLayer } ;
29+ use tower_layer:: Layer ;
2230
2331/// Default maximum capacity for the channel of events sent from a
2432/// [`Server`] to each subscribed client.
@@ -28,15 +36,81 @@ use tower_http::cors::{AllowHeaders, CorsLayer};
2836const DEFAULT_CLIENT_BUFFER_CAPACITY : usize = 1024 * 4 ;
2937
3038/// The `gRPC` server that exposes the instrumenting API
31- pub struct Server (
32- tonic:: transport:: server:: Router < tower_layer:: Stack < CorsLayer , tower_layer:: Identity > > ,
33- ) ;
39+ pub struct Server {
40+ router : tonic:: transport:: server:: Router <
41+ tower_layer:: Stack < DynamicCorsLayer , tower_layer:: Identity > ,
42+ > ,
43+ handle : ServerHandle ,
44+ }
45+
46+ /// A handle to a server that is allowed to modify its properties (such as CORS allowed origins)
47+ #[ derive( Clone ) ]
48+ pub struct ServerHandle {
49+ allowed_origins : Arc < Mutex < Vec < AllowOrigin > > > ,
50+ }
51+
52+ impl ServerHandle {
53+ pub fn allow_origin ( & self , origin : impl Into < AllowOrigin > ) {
54+ self . allowed_origins . lock ( ) . unwrap ( ) . push ( origin. into ( ) ) ;
55+ }
56+ }
3457
3558struct InstrumentService {
3659 tx : mpsc:: Sender < Command > ,
3760 health_reporter : HealthReporter ,
3861}
3962
63+ #[ derive( Clone ) ]
64+ struct DynamicCorsLayer {
65+ allowed_origins : Arc < Mutex < Vec < AllowOrigin > > > ,
66+ }
67+
68+ impl < S > Layer < S > for DynamicCorsLayer {
69+ type Service = DynamicCors < S > ;
70+
71+ fn layer ( & self , service : S ) -> Self :: Service {
72+ DynamicCors {
73+ inner : service,
74+ allowed_origins : self . allowed_origins . clone ( ) ,
75+ }
76+ }
77+ }
78+
79+ #[ derive( Debug , Clone ) ]
80+ struct DynamicCors < S > {
81+ inner : S ,
82+ allowed_origins : Arc < Mutex < Vec < AllowOrigin > > > ,
83+ }
84+
85+ type BoxFuture < ' a , T > = Pin < Box < dyn std:: future:: Future < Output = T > + Send + ' a > > ;
86+
87+ impl < S > Service < hyper:: Request < Body > > for DynamicCors < S >
88+ where
89+ S : Service < hyper:: Request < Body > , Response = hyper:: Response < BoxBody > > + Clone + Send + ' static ,
90+ S :: Future : Send + ' static ,
91+ {
92+ type Response = S :: Response ;
93+ type Error = S :: Error ;
94+ type Future = BoxFuture < ' static , Result < Self :: Response , Self :: Error > > ;
95+
96+ fn poll_ready ( & mut self , cx : & mut Context < ' _ > ) -> Poll < Result < ( ) , Self :: Error > > {
97+ self . inner . poll_ready ( cx)
98+ }
99+
100+ fn call ( & mut self , req : hyper:: Request < Body > ) -> Self :: Future {
101+ let mut cors = CorsLayer :: new ( )
102+ // allow `GET` and `POST` when accessing the resource
103+ . allow_methods ( [ Method :: GET , Method :: POST ] )
104+ . allow_headers ( AllowHeaders :: any ( ) ) ;
105+
106+ for origin in & * self . allowed_origins . lock ( ) . unwrap ( ) {
107+ cors = cors. allow_origin ( origin. clone ( ) ) ;
108+ }
109+
110+ Box :: pin ( cors. layer ( self . inner . clone ( ) ) . call ( req) )
111+ }
112+ }
113+
40114impl Server {
41115 #[ allow( clippy:: missing_panics_doc) ]
42116 pub fn new (
@@ -51,15 +125,22 @@ impl Server {
51125 . set_serving :: < InstrumentServer < InstrumentService > > ( )
52126 . now_or_never ( ) ;
53127
54- let cors = CorsLayer :: new ( )
55- // allow `GET` and `POST` when accessing the resource
56- . allow_methods ( [ Method :: GET , Method :: POST ] )
57- . allow_headers ( AllowHeaders :: any ( ) )
58- . allow_origin ( tower_http:: cors:: Any ) ;
128+ let allowed_origins =
129+ Arc :: new ( Mutex :: new ( vec ! [
130+ if option_env!( "__DEVTOOLS_LOCAL_DEVELOPMENT" ) . is_some( ) {
131+ AllowOrigin :: from( tower_http:: cors:: Any )
132+ } else {
133+ HeaderValue :: from_str( "https://devtools.crabnebula.dev" )
134+ . unwrap( )
135+ . into( )
136+ } ,
137+ ] ) ) ;
59138
60139 let router = tonic:: transport:: Server :: builder ( )
61140 . accept_http1 ( true )
62- . layer ( cors)
141+ . layer ( DynamicCorsLayer {
142+ allowed_origins : allowed_origins. clone ( ) ,
143+ } )
63144 . add_service ( tonic_web:: enable ( health_service) )
64145 . add_service ( tonic_web:: enable ( InstrumentServer :: new (
65146 InstrumentService {
@@ -71,7 +152,14 @@ impl Server {
71152 . add_service ( tonic_web:: enable ( MetadataServer :: new ( metadata_server) ) )
72153 . add_service ( tonic_web:: enable ( SourcesServer :: new ( sources_server) ) ) ;
73154
74- Self ( router)
155+ Self {
156+ router,
157+ handle : ServerHandle { allowed_origins } ,
158+ }
159+ }
160+
161+ pub fn handle ( & self ) -> ServerHandle {
162+ self . handle . clone ( )
75163 }
76164
77165 /// Consumes this [`Server`] and returns a future that will execute the server.
@@ -82,7 +170,7 @@ impl Server {
82170 pub async fn run ( self , addr : SocketAddr ) -> crate :: Result < ( ) > {
83171 tracing:: info!( "Listening on {}" , addr) ;
84172
85- self . 0 . serve ( addr) . await ?;
173+ self . router . serve ( addr) . await ?;
86174
87175 Ok ( ( ) )
88176 }
0 commit comments