Commit e78ada77 authored by Eduardo Sanz García's avatar Eduardo Sanz García Committed by Eduardo

Respond to the first port request, ignore additional ones

On Chrome, transferring the port more than once causes an error:

```
const {port1, port2} = new MessageChannel();
window.postMessage('hello', '*', [port1])
window.postMessage('hello', '*', [port1])
> Uncaught DOMException: Failed to execute 'postMessage' on 'Window': Port at index 0 is already neutered.
    at <anonymous>:1:8
```

As a result of `PortFinder` polling the host, `PortProvider` could
respond multiple times, specially when the polling frequency is high.
parent ab392e9f
......@@ -86,10 +86,6 @@ export class PortProvider {
// Create the `host-sidebar` channel immediately, while other channels are
// created on demand
this._hostSidebarChannel = new MessageChannel();
this._channels.set(
'host-sidebar',
new Map([[window, this._hostSidebarChannel]])
);
this._listeners = new ListenerCollection();
this._listen();
......@@ -233,17 +229,7 @@ export class PortProvider {
return;
}
const { channel, port } = options.allowedMessage;
// Check if channel has already been created. `host-sidebar` channel is an
// special case, because is created in the constructor.
if (channel === 'host-sidebar' && port === 'sidebar') {
this._sendPort(event, {
...options,
port: this._hostSidebarChannel.port2,
});
return;
}
const { channel } = options.allowedMessage;
let windowChannelMap = this._channels.get(channel);
if (!windowChannelMap) {
......@@ -254,11 +240,26 @@ export class PortProvider {
const source = /** @type {Window} */ (event.source);
let messageChannel = windowChannelMap.get(source);
if (!messageChannel) {
messageChannel = new MessageChannel();
windowChannelMap.set(source, messageChannel);
// Ignore the port request if the channel for the specified window has
// already been created. This is to avoid transfer the port more than once.
if (messageChannel) {
return;
}
// `host-sidebar` channel is an special case, because it is created in the
// constructor.
if (channel === 'host-sidebar') {
windowChannelMap.set(source, this._hostSidebarChannel);
this._sendPort(event, {
...options,
port: this._hostSidebarChannel.port2,
});
return;
}
messageChannel = new MessageChannel();
windowChannelMap.set(source, messageChannel);
const { port1, port2 } = messageChannel;
this._sendPort(event, { ...options, port: port1, reciprocalPort: port2 });
}
......
......@@ -159,6 +159,29 @@ describe('PortProvider', () => {
);
});
it('responds to the first valid port request, ignore additional requests', async () => {
const data = {
channel: 'host-sidebar',
port: 'sidebar',
source,
type: 'request',
};
for (let i = 0; i < 4; ++i) {
sendMessage({
data,
});
}
await delay(0);
assert.calledOnceWithExactly(
window.postMessage,
{ ...data, type: 'offer' },
window.location.origin,
[sinon.match.instanceOf(MessagePort)]
);
});
it('sends the reciprocal port of the `guest-sidebar` channel (via the sidebar port)', async () => {
sendMessage({
data: {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment