-
Notifications
You must be signed in to change notification settings - Fork 29.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
worker,fs: make FileHandle transferable
Allow passing `FileHandle` instances in the transfer list of a `.postMessage()` call. PR-URL: #33772 Backport-PR-URL: #33965 Reviewed-By: Benjamin Gruenbaum <[email protected]>
- Loading branch information
Showing
8 changed files
with
235 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
test/parallel/test-worker-message-port-transfer-fake-js-transferable-internal.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
'use strict'; | ||
const common = require('../common'); | ||
const assert = require('assert'); | ||
const fs = require('fs').promises; | ||
const { MessageChannel } = require('worker_threads'); | ||
const { once } = require('events'); | ||
|
||
// Test that overriding the internal kTransfer method of a JSTransferable does | ||
// not enable loading arbitrary code from internal Node.js core modules. | ||
|
||
(async function() { | ||
const fh = await fs.open(__filename); | ||
assert.strictEqual(fh.constructor.name, 'FileHandle'); | ||
|
||
const kTransfer = Object.getOwnPropertySymbols(Object.getPrototypeOf(fh)) | ||
.filter((symbol) => symbol.description === 'messaging_transfer_symbol')[0]; | ||
assert.strictEqual(typeof kTransfer, 'symbol'); | ||
fh[kTransfer] = () => { | ||
return { | ||
data: '✨', | ||
deserializeInfo: 'net:Socket' | ||
}; | ||
}; | ||
|
||
const { port1, port2 } = new MessageChannel(); | ||
port1.postMessage(fh, [ fh ]); | ||
port2.on('message', common.mustNotCall()); | ||
|
||
const [ exception ] = await once(process, 'uncaughtException'); | ||
|
||
assert.strictEqual(exception.message, 'Unknown deserialize spec net:Socket'); | ||
port2.close(); | ||
})().then(common.mustCall()); |
37 changes: 37 additions & 0 deletions
37
test/parallel/test-worker-message-port-transfer-fake-js-transferable.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
'use strict'; | ||
const common = require('../common'); | ||
const assert = require('assert'); | ||
const fs = require('fs').promises; | ||
const { MessageChannel } = require('worker_threads'); | ||
const { once } = require('events'); | ||
|
||
// Test that overriding the internal kTransfer method of a JSTransferable does | ||
// not enable loading arbitrary code from the disk. | ||
|
||
module.exports = { | ||
NotARealClass: common.mustNotCall() | ||
}; | ||
|
||
(async function() { | ||
const fh = await fs.open(__filename); | ||
assert.strictEqual(fh.constructor.name, 'FileHandle'); | ||
|
||
const kTransfer = Object.getOwnPropertySymbols(Object.getPrototypeOf(fh)) | ||
.filter((symbol) => symbol.description === 'messaging_transfer_symbol')[0]; | ||
assert.strictEqual(typeof kTransfer, 'symbol'); | ||
fh[kTransfer] = () => { | ||
return { | ||
data: '✨', | ||
deserializeInfo: `${__filename}:NotARealClass` | ||
}; | ||
}; | ||
|
||
const { port1, port2 } = new MessageChannel(); | ||
port1.postMessage(fh, [ fh ]); | ||
port2.on('message', common.mustNotCall()); | ||
|
||
const [ exception ] = await once(process, 'uncaughtException'); | ||
|
||
assert.match(exception.message, /Missing internal module/); | ||
port2.close(); | ||
})().then(common.mustCall()); |
65 changes: 65 additions & 0 deletions
65
test/parallel/test-worker-message-port-transfer-filehandle.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
'use strict'; | ||
const common = require('../common'); | ||
const assert = require('assert'); | ||
const fs = require('fs').promises; | ||
const vm = require('vm'); | ||
const { MessageChannel, moveMessagePortToContext } = require('worker_threads'); | ||
const { once } = require('events'); | ||
|
||
(async function() { | ||
const fh = await fs.open(__filename); | ||
|
||
const { port1, port2 } = new MessageChannel(); | ||
|
||
assert.throws(() => { | ||
port1.postMessage(fh); | ||
}, { | ||
// See the TODO about error code in node_messaging.cc. | ||
code: 'ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST' | ||
}); | ||
|
||
// Check that transferring FileHandle instances works. | ||
assert.notStrictEqual(fh.fd, -1); | ||
port1.postMessage(fh, [ fh ]); | ||
assert.strictEqual(fh.fd, -1); | ||
|
||
const [ fh2 ] = await once(port2, 'message'); | ||
assert.strictEqual(Object.getPrototypeOf(fh2), Object.getPrototypeOf(fh)); | ||
|
||
assert.deepStrictEqual(await fh2.readFile(), await fs.readFile(__filename)); | ||
await fh2.close(); | ||
|
||
assert.rejects(() => fh.readFile(), { code: 'EBADF' }); | ||
})().then(common.mustCall()); | ||
|
||
(async function() { | ||
// Check that there is no crash if the message is never read. | ||
const fh = await fs.open(__filename); | ||
|
||
const { port1 } = new MessageChannel(); | ||
|
||
assert.notStrictEqual(fh.fd, -1); | ||
port1.postMessage(fh, [ fh ]); | ||
assert.strictEqual(fh.fd, -1); | ||
})().then(common.mustCall()); | ||
|
||
(async function() { | ||
// Check that in the case of a context mismatch the message is discarded. | ||
const fh = await fs.open(__filename); | ||
|
||
const { port1, port2 } = new MessageChannel(); | ||
|
||
const ctx = vm.createContext(); | ||
const port2moved = moveMessagePortToContext(port2, ctx); | ||
port2moved.onmessage = common.mustCall((msgEvent) => { | ||
assert.strictEqual(msgEvent.data, 'second message'); | ||
port1.close(); | ||
}); | ||
port2moved.start(); | ||
|
||
assert.notStrictEqual(fh.fd, -1); | ||
port1.postMessage(fh, [ fh ]); | ||
assert.strictEqual(fh.fd, -1); | ||
|
||
port1.postMessage('second message'); | ||
})().then(common.mustCall()); |