@@ -18,6 +18,7 @@ import { connectionTokenQueryName, FileAccess, Schemas } from 'vs/base/common/ne
18
18
import { dirname , join } from 'vs/base/common/path' ;
19
19
import * as perf from 'vs/base/common/performance' ;
20
20
import * as platform from 'vs/base/common/platform' ;
21
+ import { createRegExp , escapeRegExpCharacters } from 'vs/base/common/strings' ;
21
22
import { URI } from 'vs/base/common/uri' ;
22
23
import { generateUuid } from 'vs/base/common/uuid' ;
23
24
import { findFreePort } from 'vs/base/node/ports' ;
@@ -58,6 +59,7 @@ export class RemoteExtensionHostAgentServer extends Disposable implements IServe
58
59
private readonly _managementConnections : { [ reconnectionToken : string ] : ManagementConnection } ;
59
60
private readonly _allReconnectionTokens : Set < string > ;
60
61
private readonly _webClientServer : WebClientServer | null ;
62
+ private readonly _webEndpointOriginChecker = WebEndpointOriginChecker . create ( this . _productService ) ;
61
63
62
64
private shutdownTimer : NodeJS . Timer | undefined ;
63
65
@@ -142,6 +144,14 @@ export class RemoteExtensionHostAgentServer extends Disposable implements IServe
142
144
responseHeaders [ 'Cache-Control' ] = 'public, max-age=31536000' ;
143
145
}
144
146
}
147
+
148
+ // Allow cross origin requests from the web worker extension host
149
+ responseHeaders [ 'Vary' ] = 'Origin' ;
150
+ const requestOrigin = req . headers [ 'origin' ] ;
151
+ if ( requestOrigin && this . _webEndpointOriginChecker . matches ( requestOrigin ) ) {
152
+ responseHeaders [ 'Access-Control-Allow-Origin' ] = requestOrigin ;
153
+ }
154
+
145
155
return serveFile ( this . _logService , req , res , filePath , responseHeaders ) ;
146
156
}
147
157
@@ -767,3 +777,45 @@ export async function createServer(address: string | net.AddressInfo | null, arg
767
777
}
768
778
return remoteExtensionHostAgentServer ;
769
779
}
780
+
781
+ class WebEndpointOriginChecker {
782
+
783
+ public static create ( productService : IProductService ) : WebEndpointOriginChecker {
784
+ const webEndpointUrlTemplate = productService . webEndpointUrlTemplate ;
785
+ const commit = productService . commit ;
786
+ const quality = productService . quality ;
787
+ if ( ! webEndpointUrlTemplate || ! commit || ! quality ) {
788
+ return new WebEndpointOriginChecker ( null ) ;
789
+ }
790
+
791
+ const uuid = generateUuid ( ) ;
792
+ const exampleUrl = new URL (
793
+ webEndpointUrlTemplate
794
+ . replace ( '{{uuid}}' , uuid )
795
+ . replace ( '{{commit}}' , commit )
796
+ . replace ( '{{quality}}' , quality )
797
+ ) ;
798
+ const exampleOrigin = exampleUrl . origin ;
799
+ const originRegExpSource = (
800
+ escapeRegExpCharacters ( exampleOrigin )
801
+ . replace ( uuid , '[a-zA-Z0-9\-]+' )
802
+ ) ;
803
+ try {
804
+ const originRegExp = createRegExp ( `^${ originRegExpSource } $` , true , { matchCase : false } ) ;
805
+ return new WebEndpointOriginChecker ( originRegExp ) ;
806
+ } catch ( err ) {
807
+ return new WebEndpointOriginChecker ( null ) ;
808
+ }
809
+ }
810
+
811
+ constructor (
812
+ private readonly _originRegExp : RegExp | null
813
+ ) { }
814
+
815
+ public matches ( origin : string ) : boolean {
816
+ if ( ! this . _originRegExp ) {
817
+ return false ;
818
+ }
819
+ return this . _originRegExp . test ( origin ) ;
820
+ }
821
+ }
0 commit comments