Skip to content

Commit d2ae606

Browse files
committed
Move webview protocol back to using main process
Fixes #89038 For #95955 This moves the webview local resource protocol back to the main process. It should now also handle remote cases by sending the remote data back to the main process
1 parent 0ed1be8 commit d2ae606

File tree

8 files changed

+120
-121
lines changed

8 files changed

+120
-121
lines changed

src/vs/base/common/network.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,6 @@ export namespace Schemas {
6262

6363
export const webviewPanel = 'webview-panel';
6464

65-
export const oldVscodeWebviewResource = 'vscode-resource';
66-
6765
export const vscodeWebviewResource = 'vscode-webview-resource';
6866

6967
/**

src/vs/platform/webview/common/resourceLoader.ts

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { VSBuffer, VSBufferReadableStream } from 'vs/base/common/buffer';
7+
import { CancellationToken } from 'vs/base/common/cancellation';
78
import { isUNC } from 'vs/base/common/extpath';
89
import { Schemas } from 'vs/base/common/network';
910
import { sep } from 'vs/base/common/path';
1011
import { URI } from 'vs/base/common/uri';
1112
import { IFileService } from 'vs/platform/files/common/files';
13+
import { IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver';
1214
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
15+
import { IRequestService } from 'vs/platform/request/common/request';
1316
import { getWebviewContentMimeType } from 'vs/platform/webview/common/mimeTypes';
1417

1518
export namespace WebviewResourceResponse {
@@ -63,18 +66,38 @@ export async function loadLocalResource(
6366

6467
export async function loadLocalResourceStream(
6568
requestUri: URI,
69+
options: {
70+
extensionLocation: URI | undefined;
71+
roots: ReadonlyArray<URI>;
72+
remoteConnectionData?: IRemoteConnectionData | null;
73+
},
6674
fileService: IFileService,
67-
extensionLocation: URI | undefined,
68-
roots: ReadonlyArray<URI>
75+
requestService: IRequestService,
6976
): Promise<WebviewResourceResponse.StreamResponse> {
70-
const resourceToLoad = getResourceToLoad(requestUri, extensionLocation, roots);
77+
const resourceToLoad = getResourceToLoad(requestUri, options.extensionLocation, options.roots);
7178
if (!resourceToLoad) {
7279
return WebviewResourceResponse.AccessDenied;
7380
}
81+
const mime = getWebviewContentMimeType(requestUri); // Use the original path for the mime
82+
83+
if (options.remoteConnectionData) {
84+
// Remote uris must go to the resolved server.
85+
if (resourceToLoad.scheme === Schemas.vscodeRemote || (options.extensionLocation?.scheme === REMOTE_HOST_SCHEME)) {
86+
const uri = URI.parse(`http://${options.remoteConnectionData.host}:${options.remoteConnectionData.port}`).with({
87+
path: '/vscode-remote-resource',
88+
query: `tkn=${options.remoteConnectionData.connectionToken}&path=${encodeURIComponent(resourceToLoad.path)}`,
89+
});
90+
91+
const response = await requestService.request({ url: uri.toString(true) }, CancellationToken.None);
92+
if (response.res.statusCode === 200) {
93+
return new WebviewResourceResponse.StreamSuccess(response.stream, mime);
94+
}
95+
return WebviewResourceResponse.Failed;
96+
}
97+
}
7498

7599
try {
76100
const contents = await fileService.readFileStream(resourceToLoad);
77-
const mime = getWebviewContentMimeType(requestUri); // Use the original path for the mime
78101
return new WebviewResourceResponse.StreamSuccess(contents.value, mime);
79102
} catch (err) {
80103
console.log(err);
@@ -90,20 +113,7 @@ function getResourceToLoad(
90113
const normalizedPath = normalizeRequestPath(requestUri);
91114

92115
for (const root of roots) {
93-
if (!containsResource(root, normalizedPath)) {
94-
continue;
95-
}
96-
97-
if (extensionLocation && extensionLocation.scheme === REMOTE_HOST_SCHEME) {
98-
return URI.from({
99-
scheme: REMOTE_HOST_SCHEME,
100-
authority: extensionLocation.authority,
101-
path: '/vscode-resource',
102-
query: JSON.stringify({
103-
requestResourcePath: normalizedPath.path
104-
})
105-
});
106-
} else {
116+
if (containsResource(root, normalizedPath)) {
107117
return normalizedPath;
108118
}
109119
}
@@ -123,19 +133,6 @@ function normalizeRequestPath(requestUri: URI) {
123133
query: requestUri.query,
124134
fragment: requestUri.fragment
125135
});
126-
} else if (requestUri.scheme === Schemas.oldVscodeWebviewResource) {
127-
// Modern `vscode-resource` uris puts the scheme as the authority
128-
if (requestUri.authority) {
129-
const resourceUri = URI.parse(`${requestUri.authority}:${encodeURIComponent(requestUri.path).replace(/%2F/g, '/')}`);
130-
return resourceUri.with({
131-
query: requestUri.query,
132-
fragment: requestUri.fragment
133-
});
134-
}
135-
136-
// Old style vscode-resource uris lose the scheme of the resource which means they are unable to
137-
// load a mix of local and remote content properly.
138-
return requestUri.with({ scheme: 'file' });
139136
} else {
140137
return requestUri;
141138
}

src/vs/platform/webview/common/webviewManagerService.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import { UriComponents } from 'vs/base/common/uri';
77
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
8+
import { IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver';
89

910
export const IWebviewManagerService = createDecorator<IWebviewManagerService>('webviewManagerService');
1011

@@ -13,12 +14,13 @@ export interface IWebviewManagerService {
1314

1415
registerWebview(id: string, metadata: RegisterWebviewMetadata): Promise<void>;
1516
unregisterWebview(id: string): Promise<void>;
16-
updateLocalResourceRoots(id: string, roots: UriComponents[]): Promise<void>;
17+
updateWebviewMetadata(id: string, metadataDelta: Partial<RegisterWebviewMetadata>): Promise<void>;
1718

1819
setIgnoreMenuShortcuts(webContentsId: number, enabled: boolean): Promise<void>;
1920
}
2021

2122
export interface RegisterWebviewMetadata {
2223
readonly extensionLocation: UriComponents | undefined;
2324
readonly localResourceRoots: readonly UriComponents[];
25+
readonly remoteConnectionData: IRemoteConnectionData | null;
2426
}

src/vs/platform/webview/electron-main/webviewMainService.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { webContents } from 'electron';
7+
import { URI } from 'vs/base/common/uri';
8+
import { IFileService } from 'vs/platform/files/common/files';
9+
import { IRequestService } from 'vs/platform/request/common/request';
710
import { IWebviewManagerService, RegisterWebviewMetadata } from 'vs/platform/webview/common/webviewManagerService';
811
import { WebviewProtocolProvider } from 'vs/platform/webview/electron-main/webviewProtocolProvider';
9-
import { IFileService } from 'vs/platform/files/common/files';
10-
import { UriComponents, URI } from 'vs/base/common/uri';
1112

1213
export class WebviewMainService implements IWebviewManagerService {
1314

@@ -17,23 +18,29 @@ export class WebviewMainService implements IWebviewManagerService {
1718

1819
constructor(
1920
@IFileService fileService: IFileService,
21+
@IRequestService requestService: IRequestService,
2022
) {
21-
this.protocolProvider = new WebviewProtocolProvider(fileService);
23+
this.protocolProvider = new WebviewProtocolProvider(fileService, requestService);
2224
}
2325

2426
public async registerWebview(id: string, metadata: RegisterWebviewMetadata): Promise<void> {
25-
this.protocolProvider.registerWebview(id,
26-
metadata.extensionLocation ? URI.from(metadata.extensionLocation) : undefined,
27-
metadata.localResourceRoots.map((x: UriComponents) => URI.from(x))
28-
);
27+
this.protocolProvider.registerWebview(id, {
28+
...metadata,
29+
extensionLocation: metadata.extensionLocation ? URI.from(metadata.extensionLocation) : undefined,
30+
localResourceRoots: metadata.localResourceRoots.map(x => URI.from(x))
31+
});
2932
}
3033

3134
public async unregisterWebview(id: string): Promise<void> {
3235
this.protocolProvider.unreigsterWebview(id);
3336
}
3437

35-
public async updateLocalResourceRoots(id: string, roots: UriComponents[]): Promise<void> {
36-
this.protocolProvider.updateLocalResourceRoots(id, roots.map((x: UriComponents) => URI.from(x)));
38+
public async updateWebviewMetadata(id: string, metadataDelta: Partial<RegisterWebviewMetadata>): Promise<void> {
39+
this.protocolProvider.updateWebviewMetadata(id, {
40+
...metadataDelta,
41+
localResourceRoots: metadataDelta.localResourceRoots?.map(x => URI.from(x)),
42+
extensionLocation: metadataDelta.extensionLocation ? URI.from(metadataDelta.extensionLocation) : undefined,
43+
});
3744
}
3845

3946
public async setIgnoreMenuShortcuts(webContentsId: number, enabled: boolean): Promise<void> {

src/vs/platform/webview/electron-main/webviewProtocolProvider.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,23 @@ import { Schemas } from 'vs/base/common/network';
99
import { URI } from 'vs/base/common/uri';
1010
import { streamToNodeReadable } from 'vs/base/node/stream';
1111
import { IFileService } from 'vs/platform/files/common/files';
12+
import { IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver';
13+
import { IRequestService } from 'vs/platform/request/common/request';
1214
import { loadLocalResourceStream, WebviewResourceResponse } from 'vs/platform/webview/common/resourceLoader';
1315

16+
interface WebviewMetadata {
17+
readonly extensionLocation: URI | undefined;
18+
readonly localResourceRoots: readonly URI[];
19+
readonly remoteConnectionData: IRemoteConnectionData | null;
20+
}
21+
1422
export class WebviewProtocolProvider extends Disposable {
1523

16-
private readonly webviewMetadata = new Map<string, {
17-
readonly extensionLocation: URI | undefined;
18-
readonly localResourceRoots: readonly URI[];
19-
}>();
24+
private readonly webviewMetadata = new Map<string, WebviewMetadata>();
2025

2126
constructor(
2227
@IFileService private readonly fileService: IFileService,
28+
@IRequestService private readonly requestService: IRequestService,
2329
) {
2430
super();
2531

@@ -30,7 +36,11 @@ export class WebviewProtocolProvider extends Disposable {
3036
const id = uri.authority;
3137
const metadata = this.webviewMetadata.get(id);
3238
if (metadata) {
33-
const result = await loadLocalResourceStream(uri, this.fileService, metadata.extensionLocation, metadata.localResourceRoots);
39+
const result = await loadLocalResourceStream(uri, {
40+
extensionLocation: metadata.extensionLocation,
41+
roots: metadata.localResourceRoots,
42+
remoteConnectionData: metadata.remoteConnectionData,
43+
}, this.fileService, this.requestService);
3444
if (result.type === WebviewResourceResponse.Type.Success) {
3545
return callback({
3646
statusCode: 200,
@@ -57,20 +67,20 @@ export class WebviewProtocolProvider extends Disposable {
5767
this._register(toDisposable(() => protocol.unregisterProtocol(Schemas.vscodeWebviewResource)));
5868
}
5969

60-
public registerWebview(id: string, extensionLocation: URI | undefined, localResourceRoots: readonly URI[]): void {
61-
this.webviewMetadata.set(id, { extensionLocation, localResourceRoots });
70+
public async registerWebview(id: string, metadata: WebviewMetadata): Promise<void> {
71+
this.webviewMetadata.set(id, metadata);
6272
}
6373

6474
public unreigsterWebview(id: string): void {
6575
this.webviewMetadata.delete(id);
6676
}
6777

68-
public updateLocalResourceRoots(id: string, localResourceRoots: readonly URI[]) {
78+
public async updateWebviewMetadata(id: string, metadataDelta: Partial<WebviewMetadata>): Promise<void> {
6979
const entry = this.webviewMetadata.get(id);
7080
if (entry) {
7181
this.webviewMetadata.set(id, {
72-
extensionLocation: entry.extensionLocation,
73-
localResourceRoots: localResourceRoots,
82+
...entry,
83+
...metadataDelta,
7484
});
7585
}
7686
}

src/vs/workbench/contrib/webview/electron-browser/pre/electron-index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
newFrame.contentWindow.addEventListener('mousemove', tryDispatchSyntheticMouseEvent);
6464
},
6565
rewriteCSP: (csp) => {
66-
return csp;
66+
return csp.replace(/vscode-resource:(?=(\s|;|$))/g, 'vscode-webview-resource:');
6767
},
6868
};
6969

0 commit comments

Comments
 (0)