From 0af3fc77e80d27695fee23171aa0bcd15617825a Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 15 May 2020 14:33:16 -0700 Subject: [PATCH] Fixing rewriting of some old-style vscode-resource uris that don't have explicit authorities --- .../src/singlefolder-tests/webview.test.ts | 44 ++++++++++++++----- .../platform/webview/common/resourceLoader.ts | 7 ++- .../electron-browser/webviewElement.ts | 8 +++- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts index 704d2f115ed..d8951eeb6bd 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts @@ -196,7 +196,7 @@ suite('vscode API - webview', () => { const firstResponse = getMesssage(webview); - assert.strictEqual((await firstResponse).value, 100); + assert.strictEqual(Math.round((await firstResponse).value), 100); // Swap away from the webview const doc = await vscode.workspace.openTextDocument(testDocument); @@ -207,7 +207,7 @@ suite('vscode API - webview', () => { // We should still have old scroll pos const secondResponse = await sendRecieveMessage(webview, { type: 'get' }); - assert.strictEqual(secondResponse.value, 100); + assert.strictEqual(Math.round(secondResponse.value), 100); }); conditionalTest('webviews with retainContextWhenHidden should be able to recive messages while hidden', async () => { @@ -252,29 +252,29 @@ suite('vscode API - webview', () => { }); `); - async function asWebviewUri(path: string) { - const root = await webview.webview.asWebviewUri(vscode.Uri.file(vscode.workspace.rootPath!)); + function asWebviewUri(path: string) { + const root = webview.webview.asWebviewUri(vscode.Uri.file(vscode.workspace.rootPath!)); return root.toString() + path; } { - const imagePath = await asWebviewUri('/image.png'); + const imagePath = asWebviewUri('/image.png'); const response = sendRecieveMessage(webview, { src: imagePath }); assert.strictEqual((await response).value, true); } { - const imagePath = await asWebviewUri('/no-such-image.png'); + const imagePath = asWebviewUri('/no-such-image.png'); const response = sendRecieveMessage(webview, { src: imagePath }); assert.strictEqual((await response).value, false); } { - const imagePath = vscode.Uri.file(join(vscode.workspace.rootPath!, '..', '..', '..', 'resources', 'linux', 'code.png')).with({ scheme: 'vscode-resource' }); + const imagePath = webview.webview.asWebviewUri(vscode.Uri.file(join(vscode.workspace.rootPath!, '..', '..', '..', 'resources', 'linux', 'code.png'))); const response = sendRecieveMessage(webview, { src: imagePath.toString() }); assert.strictEqual((await response).value, false); } }); - conditionalTest('webviews should allow overriding allowed resource paths using localResourceRoots', async () => { + test('webviews should allow overriding allowed resource paths using localResourceRoots', async () => { const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true, localResourceRoots: [vscode.Uri.file(join(vscode.workspace.rootPath!, 'sub'))] @@ -292,18 +292,38 @@ suite('vscode API - webview', () => { }); `); - const workspaceRootUri = vscode.Uri.file(vscode.workspace.rootPath!).with({ scheme: 'vscode-resource' }); - { - const response = sendRecieveMessage(webview, { src: workspaceRootUri.toString() + '/sub/image.png' }); + const response = sendRecieveMessage(webview, { src: webview.webview.asWebviewUri(vscode.Uri.file(vscode.workspace.rootPath! + '/sub/image.png')).toString() }); assert.strictEqual((await response).value, true); } { - const response = sendRecieveMessage(webview, { src: workspaceRootUri.toString() + '/image.png' }); + const response = sendRecieveMessage(webview, { src: webview.webview.asWebviewUri(vscode.Uri.file(vscode.workspace.rootPath! + '/image.png')).toString() }); assert.strictEqual((await response).value, false); } }); + conditionalTest('webviews using hard-coded old style vscode-resource uri should work', async () => { + const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { + enableScripts: true, + localResourceRoots: [vscode.Uri.file(join(vscode.workspace.rootPath!, 'sub'))] + })); + + const imagePath = vscode.Uri.file(join(vscode.workspace.rootPath!, 'sub', 'image.png')).with({ scheme: 'vscode-resource' }).toString(); + + webview.webview.html = createHtmlDocumentWithBody(/*html*/` + + `); + + const firstResponse = getMesssage(webview); + + assert.strictEqual((await firstResponse).value, true); + }); + test('webviews should have real view column after they are created, #56097', async () => { const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.Active }, { enableScripts: true })); diff --git a/src/vs/platform/webview/common/resourceLoader.ts b/src/vs/platform/webview/common/resourceLoader.ts index b9f9fcb1c99..0873dcdd038 100644 --- a/src/vs/platform/webview/common/resourceLoader.ts +++ b/src/vs/platform/webview/common/resourceLoader.ts @@ -114,8 +114,11 @@ function normalizeRequestPath(requestUri: URI) { return requestUri; } - // The `vscode-webview-resource` schemes encodes both the scheme and uri: - const resourceUri = URI.parse(requestUri.path.replace(/\/+(\w+)\/\//, '$1://')); + // The `vscode-webview-resource` scheme has the following format: + // + // vscode-webview-resource://id/scheme//authority?/path + // + const resourceUri = URI.parse(requestUri.path.replace(/^\/(\w+)\/{1,2}/, '$1://')); return resourceUri.with({ query: requestUri.query, fragment: requestUri.fragment diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts index 6d3c9f7cdc5..863d7efe3a8 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts @@ -390,9 +390,13 @@ export class ElectronWebviewBasedWebview extends BaseWebview impleme return value .replace(/(["'])vscode-resource:(\/\/([^\s\/'"]+?)(?=\/))?([^\s'"]+?)(["'])/gi, (match, startQuote, _1, scheme, path, endQuote) => { if (scheme) { - return `${startQuote}${Schemas.vscodeWebviewResource}:${this.id}//${scheme}${path}${endQuote}`; + return `${startQuote}${Schemas.vscodeWebviewResource}:${this.id}/${scheme}${path}${endQuote}`; } - return `${startQuote}${Schemas.vscodeWebviewResource}:${this.id}//file${path}${endQuote}`; + if (!path.startsWith('//')) { + // Add an empty authority if we don't already have one + path = '//' + path; + } + return `${startQuote}${Schemas.vscodeWebviewResource}:${this.id}/file${path}${endQuote}`; }); }