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
This commit is contained in:
Matt Bierner 2021-05-26 19:46:02 -07:00
parent 1fd2b4ed1e
commit 02968bc250

View file

@ -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<Client | undefined>}
* @returns {Promise<Client[]>}
*/
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;