diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index 0aad1cf390df3b0be9bfb9f69f0a5138133515eb..f1a9107e9032c03871c1d3fea6211d9c34c4f3a3 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -278,7 +278,7 @@ export class EnvironmentService implements IEnvironmentService { get driverHandle(): string | undefined { return this._args['driver']; } get driverVerbose(): boolean { return !!this._args['driver-verbose']; } - readonly webviewResourceRoot = 'vscode-resource:'; + readonly webviewResourceRoot = 'vscode-resource:{{resource}}'; readonly webviewCspRule = 'vscode-resource:'; constructor(private _args: ParsedArgs, private _execPath: string) { diff --git a/src/vs/workbench/api/common/extHostCodeInsets.ts b/src/vs/workbench/api/common/extHostCodeInsets.ts index 49ba7410c643e122aa5279ce08c6858163e9461b..e744e87aa314663f67a276ac48f3deb1ad95ffc0 100644 --- a/src/vs/workbench/api/common/extHostCodeInsets.ts +++ b/src/vs/workbench/api/common/extHostCodeInsets.ts @@ -11,6 +11,7 @@ import { ExtHostEditors } from 'vs/workbench/api/common/extHostTextEditors'; import * as vscode from 'vscode'; import { ExtHostEditorInsetsShape, MainThreadEditorInsetsShape } from './extHost.protocol'; import { toWebviewResource, WebviewInitData } from 'vs/workbench/api/common/shared/webview'; +import { generateUuid } from 'vs/base/common/uuid'; export class ExtHostEditorInsets implements ExtHostEditorInsetsShape { @@ -60,11 +61,12 @@ export class ExtHostEditorInsets implements ExtHostEditorInsetsShape { const webview = new class implements vscode.Webview { + private readonly _uuid = generateUuid(); private _html: string = ''; private _options: vscode.WebviewOptions; toWebviewResource(resource: vscode.Uri): vscode.Uri { - return toWebviewResource(that._initData, resource); + return toWebviewResource(that._initData, this._uuid, resource); } get cspRule(): string { diff --git a/src/vs/workbench/api/common/extHostWebview.ts b/src/vs/workbench/api/common/extHostWebview.ts index e4e4756afe9be75b410ffeefdd2500331ad536a4..5341db7fec5cf10025b973e97f63e5be1552aa32 100644 --- a/src/vs/workbench/api/common/extHostWebview.ts +++ b/src/vs/workbench/api/common/extHostWebview.ts @@ -13,40 +13,36 @@ import { Disposable } from './extHostTypes'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import * as modes from 'vs/editor/common/modes'; import { WebviewInitData, toWebviewResource } from 'vs/workbench/api/common/shared/webview'; +import { generateUuid } from 'vs/base/common/uuid'; type IconPath = URI | { light: URI, dark: URI }; export class ExtHostWebview implements vscode.Webview { - private readonly _handle: WebviewPanelHandle; - private readonly _proxy: MainThreadWebviewsShape; + private readonly _uuid: string = generateUuid(); + private _html: string; - private _options: vscode.WebviewOptions; private _isDisposed: boolean = false; public readonly _onMessageEmitter = new Emitter(); public readonly onDidReceiveMessage: Event = this._onMessageEmitter.event; constructor( - handle: WebviewPanelHandle, - proxy: MainThreadWebviewsShape, - options: vscode.WebviewOptions, - private readonly initData: WebviewInitData - ) { - this._handle = handle; - this._proxy = proxy; - this._options = options; - } + private readonly _handle: WebviewPanelHandle, + private readonly _proxy: MainThreadWebviewsShape, + private _options: vscode.WebviewOptions, + private readonly _initData: WebviewInitData + ) { } public dispose() { this._onMessageEmitter.dispose(); } public toWebviewResource(resource: vscode.Uri): vscode.Uri { - return toWebviewResource(this.initData, resource); + return toWebviewResource(this._initData, this._uuid, resource); } public get cspRule(): string { - return this.initData.webviewCspRule; + return this._initData.webviewCspRule; } public get html(): string { diff --git a/src/vs/workbench/api/common/shared/webview.ts b/src/vs/workbench/api/common/shared/webview.ts index 95320c72136dfd9cac414224d5251d9099005e0c..798f685c762370c551ebeb2403f3d4cfe43a6920 100644 --- a/src/vs/workbench/api/common/shared/webview.ts +++ b/src/vs/workbench/api/common/shared/webview.ts @@ -13,12 +13,12 @@ export interface WebviewInitData { export function toWebviewResource( initData: WebviewInitData, + uuid: string, resource: vscode.Uri ): vscode.Uri { - const rootUri = URI.parse(initData.webviewResourceRoot); - return rootUri.with({ - path: rootUri.path + resource.path, - query: resource.query, - fragment: resource.fragment, - }); + const uri = initData.webviewResourceRoot + .replace('{{resource}}', resource.toString().replace(/^\S+?:/, '')) + .replace('{{uuid}}', uuid); + + return URI.parse(uri); } diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index 947b0db9f590885fb1f6528b629d95c7f21e4598..ebb6a82e8bfb147ea4b44eac14877cf988ebb528 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -147,7 +147,7 @@ export class BrowserWorkbenchEnvironmentService implements IEnvironmentService { webviewEndpoint?: string; get webviewResourceRoot(): string { - return this.webviewEndpoint ? this.webviewEndpoint + '/vscode-resource' : 'vscode-resource:'; + return this.webviewEndpoint ? this.webviewEndpoint + '/vscode-resource{{resource}}' : 'vscode-resource:{{resource}}'; } get webviewCspRule(): string { diff --git a/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts b/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts index 5ea5164c7a16b562254c9f73436c243813181128..b36e94a31031063cdaafb07873aba30afabcbf1e 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts @@ -50,7 +50,10 @@ suite('ExtHostWebview', () => { test('toWebviewResource for desktop vscode-resource scheme', () => { const shape = createNoopMainThreadWebviews(); - const extHostWebviews = new ExtHostWebviews(SingleProxyRPCProtocol(shape), { webviewCspRule: '', webviewResourceRoot: 'vscode-resource:' }); + const extHostWebviews = new ExtHostWebviews(SingleProxyRPCProtocol(shape), { + webviewCspRule: '', + webviewResourceRoot: 'vscode-resource:{{resource}}' + }); const webview = extHostWebviews.createWebviewPanel({} as any, 'type', 'title', 1, {}); assert.strictEqual( @@ -58,6 +61,7 @@ suite('ExtHostWebview', () => { 'vscode-resource:/Users/codey/file.html', 'Unix basic' ); + assert.strictEqual( webview.webview.toWebviewResource(URI.parse('file:///Users/codey/file.html#frag')).toString(), 'vscode-resource:/Users/codey/file.html#frag', @@ -70,12 +74,11 @@ suite('ExtHostWebview', () => { 'Unix with encoding' ); - // TODO: Fix for #48403 - // assert.strictEqual( - // webview.webview.toWebviewResource(URI.parse('file://localhost/Users/codey/file.html')).toString(), - // 'vscode-resource:/Users/codey/file.html', - // 'Unix should preserve authority' - // ); + assert.strictEqual( + webview.webview.toWebviewResource(URI.parse('file://localhost/Users/codey/file.html')).toString(), + 'vscode-resource://localhost/Users/codey/file.html', + 'Unix should preserve authority' + ); assert.strictEqual( webview.webview.toWebviewResource(URI.parse('file:///c:/codey/file.txt')).toString(), @@ -83,6 +86,50 @@ suite('ExtHostWebview', () => { 'Windows C drive' ); }); + + test('toWebviewResource for web endpoint', () => { + const shape = createNoopMainThreadWebviews(); + + const extHostWebviews = new ExtHostWebviews(SingleProxyRPCProtocol(shape), { + webviewCspRule: '', + webviewResourceRoot: `https://{{uuid}}.webview.contoso.com/commit{{resource}}` + }); + const webview = extHostWebviews.createWebviewPanel({} as any, 'type', 'title', 1, {}); + + function stripEndpointUuid(input: string) { + return input.replace(/^https:\/\/[^\.]+?\./, ''); + } + + assert.strictEqual( + stripEndpointUuid(webview.webview.toWebviewResource(URI.parse('file:///Users/codey/file.html')).toString()), + 'webview.contoso.com/commit///Users/codey/file.html', + 'Unix basic' + ); + + assert.strictEqual( + stripEndpointUuid(webview.webview.toWebviewResource(URI.parse('file:///Users/codey/file.html#frag')).toString()), + 'webview.contoso.com/commit///Users/codey/file.html#frag', + 'Unix should preserve fragment' + ); + + assert.strictEqual( + stripEndpointUuid(webview.webview.toWebviewResource(URI.parse('file:///Users/codey/f%20ile.html')).toString()), + 'webview.contoso.com/commit///Users/codey/f%20ile.html', + 'Unix with encoding' + ); + + assert.strictEqual( + stripEndpointUuid(webview.webview.toWebviewResource(URI.parse('file://localhost/Users/codey/file.html')).toString()), + 'webview.contoso.com/commit//localhost/Users/codey/file.html', + 'Unix should preserve authority' + ); + + assert.strictEqual( + stripEndpointUuid(webview.webview.toWebviewResource(URI.parse('file:///c:/codey/file.txt')).toString()), + 'webview.contoso.com/commit///c%3A/codey/file.txt', + 'Windows C drive' + ); + }); });