Add explicit wait on protocol registration

Possible fix for #89038/#91506. In both cases, it looks like we try to use the protocol before it is properly registered. If this fix doesn't work, there's probably something weird going on on the electron side of things
This commit is contained in:
Matt Bierner
2020-03-02 17:18:03 -08:00
parent 2158b1aa65
commit ed8c0e4e1d
2 changed files with 46 additions and 34 deletions
@@ -113,23 +113,29 @@ class WebviewSession extends Disposable {
}
class WebviewProtocolProvider extends Disposable {
private _resolve!: () => void;
private _reject!: () => void;
public readonly ready: Promise<void>;
constructor(
handle: WebviewTagHandle,
private readonly _getExtensionLocation: () => URI | undefined,
private readonly _getLocalResourceRoots: () => ReadonlyArray<URI>,
private readonly _fileService: IFileService,
getExtensionLocation: () => URI | undefined,
getLocalResourceRoots: () => ReadonlyArray<URI>,
fileService: IFileService,
) {
super();
this._register(handle.onFirstLoad(contents => {
this.registerProtocols(contents);
}));
}
this.ready = new Promise((resolve, reject) => {
this._resolve = resolve;
this._reject = reject;
});
private registerProtocols(contents: WebContents) {
registerFileProtocol(contents, WebviewResourceScheme, this._fileService, this._getExtensionLocation(), () =>
this._getLocalResourceRoots()
);
this._register(handle.onFirstLoad(contents => {
registerFileProtocol(contents, WebviewResourceScheme, fileService, getExtensionLocation(), getLocalResourceRoots)
.then(this._resolve, this._reject);
}));
}
}
@@ -204,6 +210,7 @@ export class ElectronWebviewBasedWebview extends BaseWebview<WebviewTag> impleme
private _findStarted: boolean = false;
public extension: WebviewExtensionDescription | undefined;
private readonly _protocolProvider: WebviewProtocolProvider;
constructor(
id: string,
@@ -222,11 +229,12 @@ export class ElectronWebviewBasedWebview extends BaseWebview<WebviewTag> impleme
const webviewAndContents = this._register(new WebviewTagHandle(this.element!));
const session = this._register(new WebviewSession(webviewAndContents));
this._register(new WebviewProtocolProvider(
webviewAndContents,
() => this.extension ? this.extension.location : undefined,
() => (this.content.options.localResourceRoots || []),
fileService));
this._protocolProvider = new WebviewProtocolProvider
(webviewAndContents,
() => this.extension ? this.extension.location : undefined,
() => (this.content.options.localResourceRoots || []),
fileService);
this._register(this._protocolProvider);
this._register(new WebviewPortMappingProvider(
session,
@@ -322,7 +330,8 @@ export class ElectronWebviewBasedWebview extends BaseWebview<WebviewTag> impleme
parent.appendChild(this.element);
}
protected postMessage(channel: string, data?: any): void {
protected async postMessage(channel: string, data?: any): Promise<void> {
await this._protocolProvider.ready;
this.element?.send(channel, data);
}
@@ -14,24 +14,27 @@ export function registerFileProtocol(
extensionLocation: URI | undefined,
getRoots: () => ReadonlyArray<URI>
) {
contents.session.protocol.registerBufferProtocol(protocol, async (request, callback: any) => {
try {
const result = await loadLocalResource(URI.parse(request.url), fileService, extensionLocation, getRoots);
if (result.type === WebviewResourceResponse.Type.Success) {
return callback({
data: Buffer.from(result.data.buffer),
mimeType: result.mimeType
});
return new Promise((resolve, reject) =>
contents.session.protocol.registerBufferProtocol(protocol, async (request, callback: any) => {
try {
const result = await loadLocalResource(URI.parse(request.url), fileService, extensionLocation, getRoots);
if (result.type === WebviewResourceResponse.Type.Success) {
return callback({
data: Buffer.from(result.data.buffer),
mimeType: result.mimeType
});
}
if (result.type === WebviewResourceResponse.Type.AccessDenied) {
console.error('Webview: Cannot load resource outside of protocol root');
return callback({ error: -10 /* ACCESS_DENIED: https://cs.chromium.org/chromium/src/net/base/net_error_list.h */ });
}
} catch {
// noop
}
if (result.type === WebviewResourceResponse.Type.AccessDenied) {
console.error('Webview: Cannot load resource outside of protocol root');
return callback({ error: -10 /* ACCESS_DENIED: https://cs.chromium.org/chromium/src/net/base/net_error_list.h */ });
}
} catch {
// noop
}
return callback({ error: -2 /* FAILED: https://cs.chromium.org/chromium/src/net/base/net_error_list.h */ });
});
return callback({ error: -2 /* FAILED: https://cs.chromium.org/chromium/src/net/base/net_error_list.h */ });
}, (err) => {
err ? reject(err) : resolve();
}));
}