1'use strict'; 2const common = require('../common'); 3const assert = require('assert'); 4const fs = require('fs').promises; 5const vm = require('vm'); 6const { MessageChannel, moveMessagePortToContext } = require('worker_threads'); 7const { once } = require('events'); 8 9(async function() { 10 const fh = await fs.open(__filename); 11 12 const { port1, port2 } = new MessageChannel(); 13 14 assert.throws(() => { 15 port1.postMessage(fh); 16 }, { 17 code: 'ERR_MISSING_TRANSFERABLE_IN_TRANSFER_LIST' 18 }); 19 20 // Check that transferring FileHandle instances works. 21 assert.notStrictEqual(fh.fd, -1); 22 port1.postMessage(fh, [ fh ]); 23 assert.strictEqual(fh.fd, -1); 24 25 const [ fh2 ] = await once(port2, 'message'); 26 assert.strictEqual(Object.getPrototypeOf(fh2), Object.getPrototypeOf(fh)); 27 28 assert.deepStrictEqual(await fh2.readFile(), await fs.readFile(__filename)); 29 await fh2.close(); 30 31 assert.rejects(() => fh.readFile(), { code: 'EBADF' }); 32})().then(common.mustCall()); 33 34(async function() { 35 // Check that there is no crash if the message is never read. 36 const fh = await fs.open(__filename); 37 38 const { port1 } = new MessageChannel(); 39 40 assert.notStrictEqual(fh.fd, -1); 41 port1.postMessage(fh, [ fh ]); 42 assert.strictEqual(fh.fd, -1); 43})().then(common.mustCall()); 44 45(async function() { 46 // Check that in the case of a context mismatch the message is discarded. 47 const fh = await fs.open(__filename); 48 49 const { port1, port2 } = new MessageChannel(); 50 51 const ctx = vm.createContext(); 52 const port2moved = moveMessagePortToContext(port2, ctx); 53 port2moved.onmessage = common.mustCall((msgEvent) => { 54 assert.strictEqual(msgEvent.data, 'second message'); 55 port1.close(); 56 }); 57 // TODO(addaleax): Switch this to a 'messageerror' event once MessagePort 58 // implements EventTarget fully and in a cross-context manner. 59 port2moved.onmessageerror = common.mustCall((event) => { 60 assert.strictEqual(event.data.code, 61 'ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE'); 62 }); 63 port2moved.start(); 64 65 assert.notStrictEqual(fh.fd, -1); 66 port1.postMessage(fh, [ fh ]); 67 assert.strictEqual(fh.fd, -1); 68 69 port1.postMessage('second message'); 70})().then(common.mustCall()); 71 72(async function() { 73 // Check that a FileHandle with a read in progress cannot be transferred. 74 const fh = await fs.open(__filename); 75 76 const { port1 } = new MessageChannel(); 77 78 const readPromise = fh.readFile(); 79 assert.throws(() => { 80 port1.postMessage(fh, [fh]); 81 }, { 82 message: 'Cannot transfer FileHandle while in use', 83 name: 'DataCloneError' 84 }); 85 86 assert.deepStrictEqual(await readPromise, await fs.readFile(__filename)); 87})().then(common.mustCall()); 88 89(async function() { 90 // Check that filehandles with a close in progress cannot be transferred. 91 const fh = await fs.open(__filename); 92 93 const { port1 } = new MessageChannel(); 94 95 const closePromise = fh.close(); 96 assert.throws(() => { 97 port1.postMessage(fh, [fh]); 98 }, { 99 message: 'Cannot transfer FileHandle while in use', 100 name: 'DataCloneError' 101 }); 102 await closePromise; 103})().then(common.mustCall()); 104