From 02968bc2503027141e06a77cf519b6b3a3c92cee Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 26 May 2021 19:46:02 -0700 Subject: [PATCH] Call post message to all parent clients Fixes #124246 With certain webviews (specifically ones that use frameworks like vue I believe), we end up with two client that both are under `index.html`. This is unexpected since we usually have one under `index.html` and one under `fake.html` If we happen to pick the wrong one when posting messages, the messages are never deliverred and we simply timeout for all the requests The fix here is to post the message to all of the potentially matching clients. This should only actually be handled by a single client --- .../webview/browser/pre/service-worker.js | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/contrib/webview/browser/pre/service-worker.js b/src/vs/workbench/contrib/webview/browser/pre/service-worker.js index 670aad0e54d..59be713aa9c 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/service-worker.js +++ b/src/vs/workbench/contrib/webview/browser/pre/service-worker.js @@ -243,8 +243,8 @@ async function processResourceRequest(event, requestUrl) { return response.clone(); } - const parentClient = await getOuterIframeClient(webviewId); - if (!parentClient) { + const parentClients = await getOuterIframeClient(webviewId); + if (!parentClients.length) { console.log('Could not find parent client for request'); return notFound(); } @@ -258,15 +258,17 @@ async function processResourceRequest(event, requestUrl) { const scheme = firstHostSegment.split('+', 1)[0]; const authority = firstHostSegment.slice(scheme.length + 1); // may be empty - parentClient.postMessage({ - channel: 'load-resource', - id: requestId, - path: decodeURIComponent(requestUrl.pathname), - scheme, - authority, - query: requestUrl.search.replace(/^\?/, ''), - ifNoneMatch: cached?.headers.get('ETag'), - }); + for (const parentClient of parentClients) { + parentClient.postMessage({ + channel: 'load-resource', + id: requestId, + path: decodeURIComponent(requestUrl.pathname), + scheme, + authority, + query: requestUrl.search.replace(/^\?/, ''), + ifNoneMatch: cached?.headers.get('ETag'), + }); + } return promise.then(entry => resolveResourceEntry(entry, cached)); } @@ -308,18 +310,20 @@ async function processLocalhostRequest(event, requestUrl) { }); }; - const parentClient = await getOuterIframeClient(webviewId); - if (!parentClient) { + const parentClients = await getOuterIframeClient(webviewId); + if (!parentClients.length) { console.log('Could not find parent client for request'); return notFound(); } const { requestId, promise } = localhostRequestStore.create(); - parentClient.postMessage({ - channel: 'load-localhost', - origin: origin, - id: requestId, - }); + for (const parentClient of parentClients) { + parentClient.postMessage({ + channel: 'load-localhost', + origin: origin, + id: requestId, + }); + } return promise.then(resolveRedirect); } @@ -335,11 +339,11 @@ function getWebviewIdForClient(client) { /** * @param {string} webviewId - * @returns {Promise} + * @returns {Promise} */ async function getOuterIframeClient(webviewId) { const allClients = await sw.clients.matchAll({ includeUncontrolled: true }); - return allClients.find(client => { + return allClients.filter(client => { const clientUrl = new URL(client.url); const hasExpectedPathName = (clientUrl.pathname === `${rootPath}/` || clientUrl.pathname === `${rootPath}/index.html` || clientUrl.pathname === `${rootPath}/electron-browser-index.html`); return hasExpectedPathName && clientUrl.searchParams.get('id') === webviewId;