"use strict"; const global = this; add_task(async function test_structuredCloneHolder() { let principal = Services.scriptSecurityManager.createContentPrincipal( Services.io.newURI("http://example.com/"), {} ); let sandbox = Cu.Sandbox(principal); const obj = { foo: [{ bar: "baz" }] }; let holder = new StructuredCloneHolder(obj); // Test same-compartment deserialization let res = holder.deserialize(global, true); notEqual( res, obj, "Deserialized result is a different object from the original" ); deepEqual( res, obj, "Deserialized result is deeply equivalent to the original" ); equal( Cu.getObjectPrincipal(res), Cu.getObjectPrincipal(global), "Deserialized result has the correct principal" ); // Test non-object-value round-trip. equal( new StructuredCloneHolder("foo").deserialize(global), "foo", "Round-tripping non-object values works as expected" ); // Test cross-compartment deserialization res = holder.deserialize(sandbox, true); notEqual( res, obj, "Cross-compartment-deserialized result is a different object from the original" ); deepEqual( res, obj, "Cross-compartment-deserialized result is deeply equivalent to the original" ); equal( Cu.getObjectPrincipal(res), principal, "Cross-compartment-deserialized result has the correct principal" ); // Test message manager transportability const MSG = "StructuredCloneHolder"; let resultPromise = new Promise(resolve => { Services.ppmm.addMessageListener(MSG, resolve); }); Services.cpmm.sendAsyncMessage(MSG, holder); res = await resultPromise; ok( res.data instanceof StructuredCloneHolder, "Sending structured clone holders through message managers works as expected" ); deepEqual( res.data.deserialize(global, true), obj, "Sending structured clone holders through message managers works as expected" ); // Test that attempting to deserialize a neutered holder throws. deepEqual( holder.deserialize(global), obj, "Deserialized result is correct when discarding data" ); Assert.throws( () => holder.deserialize(global), err => err.result == Cr.NS_ERROR_NOT_INITIALIZED, "Attempting to deserialize neutered holder throws" ); Assert.throws( () => holder.deserialize(global, true), err => err.result == Cr.NS_ERROR_NOT_INITIALIZED, "Attempting to deserialize neutered holder throws" ); }); // Test that X-rays passed to an exported function are serialized // through their exported wrappers. add_task(async function test_structuredCloneHolder_xray() { let principal = Services.scriptSecurityManager.createContentPrincipal( Services.io.newURI("http://example.com/"), {} ); let sandbox1 = Cu.Sandbox(principal, { wantXrays: true }); let sandbox2 = Cu.Sandbox(principal, { wantXrays: true }); Cu.evalInSandbox(`this.x = {y: "z", get z() { return "q" }}`, sandbox2); sandbox1.x = sandbox2.x; let holder; Cu.exportFunction( function serialize(val) { holder = new StructuredCloneHolder(val, sandbox1); }, sandbox1, { defineAs: "serialize" } ); Cu.evalInSandbox(`serialize(x)`, sandbox1); const obj = { y: "z" }; let res = holder.deserialize(global); deepEqual( res, obj, "Deserialized result is deeply equivalent to the expected object" ); deepEqual( res, sandbox2.x, "Deserialized result is deeply equivalent to the X-ray-wrapped object" ); equal( Cu.getObjectPrincipal(res), Cu.getObjectPrincipal(global), "Deserialized result has the correct principal" ); });