Skip to content

Commit

Permalink
Maintain backwards compatibility with wire format from 4.3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Nemikolh committed Mar 6, 2023
1 parent dffe905 commit 3df8b5c
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 25 deletions.
4 changes: 4 additions & 0 deletions karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ module.exports = function (config) {
pattern: "dist/**/*.@(mjs|js)",
included: false,
},
{
pattern: "node_modules/comlink/dist/esm/**/*.@(mjs|js)",
type: "module",
},
{
pattern: "tests/*.test.js",
type: "module",
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@rollup/plugin-typescript": "11.0.0",
"chai": "^4.3.7",
"conditional-type-checks": "1.0.6",
"comlink": "4.3.0",
"husky": "8.0.3",
"karma": "6.4.1",
"karma-chai": "0.1.0",
Expand Down
13 changes: 11 additions & 2 deletions src/comlink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,10 +303,17 @@ export function expose(
console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);
return;
}
const { id, type, path } = {
const { id, type, path, wireType } = {
path: [] as string[],
...(ev.data as Message),
...(ev.data as Message | WireValue),
};

// We ignore messages that are not for this event listener.
// This only happen when two-way communication is used.
if (wireType) {
return;
}

const argumentList = (ev.data.argumentList || []).map(fromWireValue);
let returnValue;
try {
Expand Down Expand Up @@ -568,6 +575,7 @@ function toWireValue(value: any): [WireValue, Transferable[]] {
return [
{
type: WireValueType.HANDLER,
wireType: true,
name,
value: serializedValue,
},
Expand All @@ -578,6 +586,7 @@ function toWireValue(value: any): [WireValue, Transferable[]] {
return [
{
type: WireValueType.RAW,
wireType: true,
value,
},
transferCache.get(value) || [],
Expand Down
43 changes: 22 additions & 21 deletions src/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,23 @@ export interface Endpoint extends EventSource {
}

export const enum WireValueType {
RAW = "RAW",
PROXY = "PROXY",
THROW = "THROW",
HANDLER = "HANDLER",
RAW,
PROXY,
THROW,
HANDLER,
}

export interface RawWireValue {
id?: string;
type: WireValueType.RAW;
wireType?: true;
value: {};
}

export interface HandlerWireValue {
id?: string;
type: WireValueType.HANDLER;
wireType?: true;
name: string;
value: unknown;
}
Expand All @@ -57,48 +59,47 @@ export type WireValue = RawWireValue | HandlerWireValue;
export type MessageID = string;

export const enum MessageType {
GET = "GET",
SET = "SET",
APPLY = "APPLY",
CONSTRUCT = "CONSTRUCT",
ENDPOINT = "ENDPOINT",
RELEASE = "RELEASE",
GET,
SET,
APPLY,
CONSTRUCT,
ENDPOINT,
RELEASE,
}

export interface GetMessage {
interface BaseMessage {
id?: MessageID;
wireType?: undefined;
}

export interface GetMessage extends BaseMessage {
type: MessageType.GET;
path: string[];
}

export interface SetMessage {
id?: MessageID;
export interface SetMessage extends BaseMessage {
type: MessageType.SET;
path: string[];
value: WireValue;
}

export interface ApplyMessage {
id?: MessageID;
export interface ApplyMessage extends BaseMessage {
type: MessageType.APPLY;
path: string[];
argumentList: WireValue[];
}

export interface ConstructMessage {
id?: MessageID;
export interface ConstructMessage extends BaseMessage {
type: MessageType.CONSTRUCT;
path: string[];
argumentList: WireValue[];
}

export interface EndpointMessage {
id?: MessageID;
export interface EndpointMessage extends BaseMessage {
type: MessageType.ENDPOINT;
}

export interface ReleaseMessage {
id?: MessageID;
export interface ReleaseMessage extends BaseMessage {
type: MessageType.RELEASE;
}

Expand Down
4 changes: 2 additions & 2 deletions tests/fixtures/attack-iframe.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
// send back a message to modify the prototype
parent.postMessage(
{
type: "SET",
value: { type: "RAW", value: "x" },
type: 1 /* MessageType.SET */,
value: { type: 0 /* WireValueType.RAW */, value: "x" },
path: ["__proto__", "foo"],
},
"*"
Expand Down
29 changes: 29 additions & 0 deletions tests/fixtures/oldcomlink.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<script type="module">
// We import v4.3.0 instead of latest main
import * as Comlink from "/base/node_modules/comlink/dist/esm/comlink.mjs";

const parentEndpoint = Comlink.windowEndpoint(self.parent);

class Test {
add(a, b) {
return a + b;
}

callme(port) {
Comlink.wrap(port).maybe();
}

pong(ping) {
return ping;
}
}

Comlink.expose(new Test(), parentEndpoint);
Comlink.transferHandlers.set("pingpong", {
canHandle: (obj) => obj === "ping",
serialize: (obj) => {
return ["pong", []];
},
deserialize: (obj) => "ping",
});
</script>
74 changes: 74 additions & 0 deletions tests/oldcomlink.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* Copyright 2017 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as Comlink from "/base/dist/esm/comlink.mjs";

describe("Comlink across versions (4.3.0 with latest main)", function () {
let oldTruncateThreshold;

beforeEach(function () {
oldTruncateThreshold = chai.config.truncateThreshold;
chai.config.truncateThreshold = 0;
this.ifr = document.createElement("iframe");
this.ifr.sandbox.add("allow-scripts", "allow-same-origin");
this.ifr.src = "/base/tests/fixtures/oldcomlink.html";
document.body.appendChild(this.ifr);
return new Promise((resolve) => (this.ifr.onload = resolve));
});

afterEach(function () {
this.ifr.remove();
chai.config.truncateThreshold = oldTruncateThreshold;
});

it("can expose, wrap and transfer", async function () {
let notcalled = true;
let error = "";
window.addEventListener("unhandledrejection", (ev) => {
notcalled = false;
error = ev.reason;
});

let maybecalled = false;
class Test {
maybe() {
maybecalled = true;
}
}
const channel = new MessageChannel();
Comlink.expose(new Test(), channel.port1);

const iframe = Comlink.windowEndpoint(this.ifr.contentWindow);
const proxy = Comlink.wrap(iframe);

expect(await proxy.add(1, 3)).to.equal(4);
await proxy.callme(Comlink.transfer(channel.port2, [channel.port2]));

expect(maybecalled).to.equal(true);
expect(error).to.equal("");
expect(notcalled).to.equal(true);
});

it("works with custom handlers", async function () {
const iframe = Comlink.windowEndpoint(this.ifr.contentWindow);
const proxy = Comlink.wrap(iframe);

Comlink.transferHandlers.set("pingpong", {
canHandle: (obj) => obj === "ping" || obj === "pong",
serialize: (obj) => [obj, []],
deserialize: (obj) => obj,
});

expect(await proxy.pong("ping")).to.equal("pong");
});
});

0 comments on commit 3df8b5c

Please sign in to comment.