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