From a0330948fe9a85ee8f25bb357fcc56f9cb4ffcee Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Tue, 3 May 2022 21:47:08 +0200 Subject: [PATCH] commit in remote resource route --- src/vs/base/common/network.ts | 7 ++++++- src/vs/code/electron-main/app.ts | 2 +- .../browser/remoteAuthorityResolverService.ts | 4 +++- .../remoteAuthorityResolverService.ts | 5 ++++- .../remoteAuthorityResolverService.test.ts | 5 ++++- .../server/node/remoteExtensionHostAgentServer.ts | 13 +++++++++++-- src/vs/server/node/webClientServer.ts | 6 +++--- src/vs/workbench/browser/web.main.ts | 2 +- src/vs/workbench/electron-sandbox/desktop.main.ts | 2 +- .../test/browser/configurationService.test.ts | 6 +++--- 10 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts index d74f249a405..2dcb54c0076 100644 --- a/src/vs/base/common/network.ts +++ b/src/vs/base/common/network.ts @@ -112,6 +112,7 @@ class RemoteAuthoritiesImpl { private readonly _connectionTokens: { [authority: string]: string | undefined } = Object.create(null); private _preferredWebSchema: 'http' | 'https' = 'http'; private _delegate: ((uri: URI) => URI) | null = null; + private _remoteResourcesPath: string = `/${Schemas.vscodeRemoteResource}`; setPreferredWebSchema(schema: 'http' | 'https') { this._preferredWebSchema = schema; @@ -121,6 +122,10 @@ class RemoteAuthoritiesImpl { this._delegate = delegate; } + setProductRoutePrefix(product: { quality?: string; commit?: string }): void { + this._remoteResourcesPath = `/${product.quality ?? 'oss'}-${product.commit ?? 'dev'}/${Schemas.vscodeRemoteResource}`; + } + set(authority: string, host: string, port: number): void { this._hosts[authority] = host; this._ports[authority] = port; @@ -152,7 +157,7 @@ class RemoteAuthoritiesImpl { return URI.from({ scheme: platform.isWeb ? this._preferredWebSchema : Schemas.vscodeRemoteResource, authority: `${host}:${port}`, - path: `/vscode-remote-resource`, + path: this._remoteResourcesPath, query }); } diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 169ba778fe1..4bc4a432ceb 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -263,7 +263,7 @@ export class CodeApplication extends Disposable { // remote extension schemes have the following format // http://127.0.0.1:/vscode-remote-resource?path= - if (!uri.path.includes(Schemas.vscodeRemoteResource) && contentTypes.some(contentType => contentType.toLowerCase().includes('image/svg'))) { + if (!uri.path.endsWith(Schemas.vscodeRemoteResource) && contentTypes.some(contentType => contentType.toLowerCase().includes('image/svg'))) { return callback({ cancel: !isSvgRequestFromSafeContext(details) }); } } diff --git a/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts index a50828715f2..db5fede918d 100644 --- a/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts +++ b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts @@ -7,6 +7,7 @@ import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { RemoteAuthorities } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; +import { IProductService } from 'vs/platform/product/common/productService'; import { IRemoteAuthorityResolverService, IRemoteConnectionData, ResolvedAuthority, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver'; export class RemoteAuthorityResolverService extends Disposable implements IRemoteAuthorityResolverService { @@ -20,7 +21,7 @@ export class RemoteAuthorityResolverService extends Disposable implements IRemot private readonly _connectionToken: string | undefined; private readonly _connectionTokens: Map; - constructor(connectionToken: string | undefined, resourceUriProvider: ((uri: URI) => URI) | undefined) { + constructor(@IProductService productService: IProductService, connectionToken: string | undefined, resourceUriProvider: ((uri: URI) => URI) | undefined) { super(); this._cache = new Map(); this._connectionToken = connectionToken; @@ -28,6 +29,7 @@ export class RemoteAuthorityResolverService extends Disposable implements IRemot if (resourceUriProvider) { RemoteAuthorities.setDelegate(resourceUriProvider); } + RemoteAuthorities.setProductRoutePrefix(productService); } async resolveAuthority(authority: string): Promise { diff --git a/src/vs/platform/remote/electron-sandbox/remoteAuthorityResolverService.ts b/src/vs/platform/remote/electron-sandbox/remoteAuthorityResolverService.ts index 13353935b7d..641d1ae328e 100644 --- a/src/vs/platform/remote/electron-sandbox/remoteAuthorityResolverService.ts +++ b/src/vs/platform/remote/electron-sandbox/remoteAuthorityResolverService.ts @@ -8,6 +8,7 @@ import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { RemoteAuthorities } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; +import { IProductService } from 'vs/platform/product/common/productService'; import { IRemoteAuthorityResolverService, IRemoteConnectionData, ResolvedAuthority, ResolvedOptions, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver'; class PendingPromise { @@ -48,12 +49,14 @@ export class RemoteAuthorityResolverService extends Disposable implements IRemot private readonly _canonicalURIRequests: Map>; private _canonicalURIProvider: ((uri: URI) => Promise) | null; - constructor() { + constructor(@IProductService productService: IProductService) { super(); this._resolveAuthorityRequests = new Map>(); this._connectionTokens = new Map(); this._canonicalURIRequests = new Map>(); this._canonicalURIProvider = null; + + RemoteAuthorities.setProductRoutePrefix(productService); } resolveAuthority(authority: string): Promise { diff --git a/src/vs/platform/remote/test/electron-sandbox/remoteAuthorityResolverService.test.ts b/src/vs/platform/remote/test/electron-sandbox/remoteAuthorityResolverService.test.ts index 81f17b25ed2..a4625318088 100644 --- a/src/vs/platform/remote/test/electron-sandbox/remoteAuthorityResolverService.test.ts +++ b/src/vs/platform/remote/test/electron-sandbox/remoteAuthorityResolverService.test.ts @@ -4,12 +4,15 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; +import product from 'vs/platform/product/common/product'; +import { IProductService } from 'vs/platform/product/common/productService'; import { RemoteAuthorityResolverError, RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-sandbox/remoteAuthorityResolverService'; suite('RemoteAuthorityResolverService', () => { test('issue #147318: RemoteAuthorityResolverError keeps the same type', async () => { - const service = new RemoteAuthorityResolverService(); + const productService: IProductService = { _serviceBrand: undefined, ...product }; + const service = new RemoteAuthorityResolverService(productService); const result = service.resolveAuthority('test+x'); service._setResolvedAuthorityError('test+x', new RemoteAuthorityResolverError('something', RemoteAuthorityResolverErrorCode.TemporarilyNotAvailable)); try { diff --git a/src/vs/server/node/remoteExtensionHostAgentServer.ts b/src/vs/server/node/remoteExtensionHostAgentServer.ts index 224d368bc38..38a0f103915 100644 --- a/src/vs/server/node/remoteExtensionHostAgentServer.ts +++ b/src/vs/server/node/remoteExtensionHostAgentServer.ts @@ -11,6 +11,7 @@ import { performance } from 'perf_hooks'; import * as url from 'url'; import { LoaderStats } from 'vs/base/common/amd'; import { VSBuffer } from 'vs/base/common/buffer'; +import { CharCode } from 'vs/base/common/charCode'; import { onUnexpectedError, setUnexpectedErrorHandler } from 'vs/base/common/errors'; import { isEqualOrParent } from 'vs/base/common/extpath'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; @@ -61,6 +62,8 @@ export class RemoteExtensionHostAgentServer extends Disposable implements IServe private readonly _webClientServer: WebClientServer | null; private readonly _webEndpointOriginChecker = WebEndpointOriginChecker.create(this._productService); + private readonly _routePrefix: string; + private shutdownTimer: NodeJS.Timer | undefined; constructor( @@ -75,12 +78,14 @@ export class RemoteExtensionHostAgentServer extends Disposable implements IServe ) { super(); + this._routePrefix = `/${_productService.quality ?? 'oss'}-${_productService.commit ?? 'dev'}`; + this._extHostConnections = Object.create(null); this._managementConnections = Object.create(null); this._allReconnectionTokens = new Set(); this._webClientServer = ( hasWebClient - ? this._instantiationService.createInstance(WebClientServer, this._connectionToken) + ? this._instantiationService.createInstance(WebClientServer, this._routePrefix, this._connectionToken) : null ); this._logService.info(`Extension host agent started.`); @@ -97,12 +102,16 @@ export class RemoteExtensionHostAgentServer extends Disposable implements IServe } const parsedUrl = url.parse(req.url, true); - const pathname = parsedUrl.pathname; + let pathname = parsedUrl.pathname; if (!pathname) { return serveError(req, res, 400, `Bad request.`); } + if (pathname.startsWith(this._routePrefix) && pathname.charCodeAt(this._routePrefix.length) === CharCode.Slash) { + pathname = pathname.substring(this._routePrefix.length); + } + // Version if (pathname === '/version') { res.writeHead(200, { 'Content-Type': 'text/plain' }); diff --git a/src/vs/server/node/webClientServer.ts b/src/vs/server/node/webClientServer.ts index 6053e046a51..6737f469de1 100644 --- a/src/vs/server/node/webClientServer.ts +++ b/src/vs/server/node/webClientServer.ts @@ -99,6 +99,7 @@ export class WebClientServer { private readonly _callbackRoute: string; constructor( + readonly routePrefix: string, private readonly _connectionToken: ServerConnectionToken, @IServerEnvironmentService private readonly _environmentService: IServerEnvironmentService, @ILogService private readonly _logService: ILogService, @@ -106,9 +107,8 @@ export class WebClientServer { @IProductService private readonly _productService: IProductService, ) { this._webExtensionResourceUrlTemplate = this._productService.extensionsGallery?.resourceUrlTemplate ? URI.parse(this._productService.extensionsGallery.resourceUrlTemplate) : undefined; - const qualityAndCommit = `${_productService.quality ?? 'oss'}-${_productService.commit ?? 'dev'}`; - this._staticRoute = `/${qualityAndCommit}/static`; - this._callbackRoute = `/${qualityAndCommit}/callback`; + this._staticRoute = `${routePrefix}/static`; + this._callbackRoute = `${routePrefix}/callback`; } /** diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index e8ca913a532..0415fcae51f 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -185,7 +185,7 @@ export class BrowserMain extends Disposable { // Remote const connectionToken = environmentService.options.connectionToken || getCookieValue(connectionTokenCookieName); - const remoteAuthorityResolverService = new RemoteAuthorityResolverService(connectionToken, this.configuration.resourceUriProvider); + const remoteAuthorityResolverService = new RemoteAuthorityResolverService(productService, connectionToken, this.configuration.resourceUriProvider); serviceCollection.set(IRemoteAuthorityResolverService, remoteAuthorityResolverService); // Signing diff --git a/src/vs/workbench/electron-sandbox/desktop.main.ts b/src/vs/workbench/electron-sandbox/desktop.main.ts index 7e658a10cdc..98b95174864 100644 --- a/src/vs/workbench/electron-sandbox/desktop.main.ts +++ b/src/vs/workbench/electron-sandbox/desktop.main.ts @@ -187,7 +187,7 @@ export class DesktopMain extends Disposable { serviceCollection.set(ISharedProcessWorkerWorkbenchService, sharedProcessWorkerWorkbenchService); // Remote - const remoteAuthorityResolverService = new RemoteAuthorityResolverService(); + const remoteAuthorityResolverService = new RemoteAuthorityResolverService(productService); serviceCollection.set(IRemoteAuthorityResolverService, remoteAuthorityResolverService); diff --git a/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts b/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts index db9b1eeff33..352fd8e9d7e 100644 --- a/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts +++ b/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts @@ -77,7 +77,7 @@ suite('WorkspaceContextService - Folder', () => { const environmentService = TestEnvironmentService; fileService.registerProvider(Schemas.vscodeUserData, disposables.add(new FileUserDataProvider(ROOT.scheme, fileSystemProvider, Schemas.vscodeUserData, new NullLogService()))); - testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, fileService, new RemoteAgentService(null, environmentService, TestProductService, new RemoteAuthorityResolverService(undefined, undefined), new SignService(undefined), new NullLogService()), new UriIdentityService(fileService), new NullLogService())); + testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, fileService, new RemoteAgentService(null, environmentService, TestProductService, new RemoteAuthorityResolverService(TestProductService, undefined, undefined), new SignService(undefined), new NullLogService()), new UriIdentityService(fileService), new NullLogService())); await (testObject).initialize(convertToWorkspacePayload(folder)); }); @@ -117,7 +117,7 @@ suite('WorkspaceContextService - Folder', () => { const environmentService = TestEnvironmentService; fileService.registerProvider(Schemas.vscodeUserData, disposables.add(new FileUserDataProvider(ROOT.scheme, fileSystemProvider, Schemas.vscodeUserData, new NullLogService()))); - const testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, fileService, new RemoteAgentService(null, environmentService, TestProductService, new RemoteAuthorityResolverService(undefined, undefined), new SignService(undefined), new NullLogService()), new UriIdentityService(fileService), new NullLogService())); + const testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, fileService, new RemoteAgentService(null, environmentService, TestProductService, new RemoteAuthorityResolverService(TestProductService, undefined, undefined), new SignService(undefined), new NullLogService()), new UriIdentityService(fileService), new NullLogService())); await (testObject).initialize(convertToWorkspacePayload(folder)); const actual = testObject.getWorkspaceFolder(joinPath(folder, 'a')); @@ -137,7 +137,7 @@ suite('WorkspaceContextService - Folder', () => { const environmentService = TestEnvironmentService; fileService.registerProvider(Schemas.vscodeUserData, disposables.add(new FileUserDataProvider(ROOT.scheme, fileSystemProvider, Schemas.vscodeUserData, new NullLogService()))); - const testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, fileService, new RemoteAgentService(null, environmentService, TestProductService, new RemoteAuthorityResolverService(undefined, undefined), new SignService(undefined), new NullLogService()), new UriIdentityService(fileService), new NullLogService())); + const testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, fileService, new RemoteAgentService(null, environmentService, TestProductService, new RemoteAuthorityResolverService(TestProductService, undefined, undefined), new SignService(undefined), new NullLogService()), new UriIdentityService(fileService), new NullLogService())); await (testObject).initialize(convertToWorkspacePayload(folder));