Support transferable objects in web worker for zero copy support
This commit is contained in:
parent
89df70cbe0
commit
ab68d4b997
|
@ -41,6 +41,7 @@ export default {
|
||||||
ignore_mdc_error: false, // fail on decrypt if message is not integrity protected
|
ignore_mdc_error: false, // fail on decrypt if message is not integrity protected
|
||||||
rsa_blinding: true,
|
rsa_blinding: true,
|
||||||
useNative: true, // use native node.js crypto and Web Crypto apis (if available)
|
useNative: true, // use native node.js crypto and Web Crypto apis (if available)
|
||||||
|
zeroCopy: false, // use transferable objects between the Web Worker and main thread
|
||||||
debug: false,
|
debug: false,
|
||||||
show_version: true,
|
show_version: true,
|
||||||
show_comment: true,
|
show_comment: true,
|
||||||
|
|
29
src/util.js
29
src/util.js
|
@ -54,6 +54,35 @@ export default {
|
||||||
return / </.test(data) && />$/.test(data);
|
return / </.test(data) && />$/.test(data);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get transferable objects to pass buffers with zero copy (similar to "pass by reference" in C++)
|
||||||
|
* See: https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage
|
||||||
|
* @param {Object} options the options object to be passed to the web worker
|
||||||
|
* @return {Array<ArrayBuffer>} an array of binary data to be passed
|
||||||
|
*/
|
||||||
|
getTransferables: function(obj) {
|
||||||
|
if (config.zeroCopy && Object.prototype.isPrototypeOf(obj)) {
|
||||||
|
const transferables = [];
|
||||||
|
this.collectBuffers(obj, transferables);
|
||||||
|
return transferables;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
collectBuffers: function(obj, collection) {
|
||||||
|
if (!obj) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.isUint8Array(obj) && collection.indexOf(obj.buffer) === -1) {
|
||||||
|
collection.push(obj.buffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Object.prototype.isPrototypeOf(obj)) {
|
||||||
|
for (let key in obj) { // recursively search all children
|
||||||
|
this.collectBuffers(obj[key], collection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
readNumber: function (bytes) {
|
readNumber: function (bytes) {
|
||||||
var n = 0;
|
var n = 0;
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
import util from '../util.js';
|
||||||
import crypto from '../crypto';
|
import crypto from '../crypto';
|
||||||
import packet from '../packet';
|
import packet from '../packet';
|
||||||
import * as key from '../key.js';
|
import * as key from '../key.js';
|
||||||
|
@ -100,7 +101,7 @@ AsyncProxy.prototype.onMessage = function(event) {
|
||||||
*/
|
*/
|
||||||
AsyncProxy.prototype.seedRandom = function(size) {
|
AsyncProxy.prototype.seedRandom = function(size) {
|
||||||
const buf = this.getRandomBuffer(size);
|
const buf = this.getRandomBuffer(size);
|
||||||
this.worker.postMessage({ event:'seed-random', buf });
|
this.worker.postMessage({ event:'seed-random', buf }, util.getTransferables.call(util, buf));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -135,7 +136,7 @@ AsyncProxy.prototype.terminate = function() {
|
||||||
AsyncProxy.prototype.delegate = function(method, options) {
|
AsyncProxy.prototype.delegate = function(method, options) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// clone packets (for web worker structured cloning algorithm)
|
// clone packets (for web worker structured cloning algorithm)
|
||||||
this.worker.postMessage({ event:method, options:clonePackets(options) });
|
this.worker.postMessage({ event:method, options:clonePackets(options) }, util.getTransferables.call(util, options));
|
||||||
|
|
||||||
// remember to handle parsing cloned packets from worker
|
// remember to handle parsing cloned packets from worker
|
||||||
this.tasks.push({ resolve: data => resolve(parseClonedPackets(data, method)), reject });
|
this.tasks.push({ resolve: data => resolve(parseClonedPackets(data, method)), reject });
|
||||||
|
|
|
@ -163,7 +163,7 @@ function clonePackets(data) {
|
||||||
|
|
||||||
function response(event) {
|
function response(event) {
|
||||||
if (window.openpgp.crypto.random.randomBuffer.size < MIN_SIZE_RANDOM_BUFFER) {
|
if (window.openpgp.crypto.random.randomBuffer.size < MIN_SIZE_RANDOM_BUFFER) {
|
||||||
postMessage({event: 'request-seed'});
|
self.postMessage({event: 'request-seed'});
|
||||||
}
|
}
|
||||||
postMessage(event);
|
self.postMessage(event, window.openpgp.util.getTransferables.call(window.openpgp.util, event.data));
|
||||||
}
|
}
|
|
@ -335,7 +335,7 @@ describe('OpenPGP.js public api tests', function() {
|
||||||
var password1 = 'I am a password';
|
var password1 = 'I am a password';
|
||||||
var password2 = 'I am another password';
|
var password2 = 'I am another password';
|
||||||
|
|
||||||
var privateKey, publicKey;
|
var privateKey, publicKey, zeroCopyVal;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
publicKey = openpgp.key.readArmored(pub_key);
|
publicKey = openpgp.key.readArmored(pub_key);
|
||||||
|
@ -344,6 +344,11 @@ describe('OpenPGP.js public api tests', function() {
|
||||||
privateKey = openpgp.key.readArmored(priv_key);
|
privateKey = openpgp.key.readArmored(priv_key);
|
||||||
expect(privateKey.keys).to.have.length(1);
|
expect(privateKey.keys).to.have.length(1);
|
||||||
expect(privateKey.err).to.not.exist;
|
expect(privateKey.err).to.not.exist;
|
||||||
|
zeroCopyVal = openpgp.config.zeroCopy;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
openpgp.config.zeroCopy = zeroCopyVal;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Decrypting key with wrong passphrase returns false', function () {
|
it('Decrypting key with wrong passphrase returns false', function () {
|
||||||
|
@ -608,6 +613,30 @@ describe('OpenPGP.js public api tests', function() {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should encrypt and decrypt with binary data and transferable objects', function(done) {
|
||||||
|
openpgp.config.zeroCopy = true; // activate transferable objects
|
||||||
|
var encOpt = {
|
||||||
|
data: new Uint8Array([0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01]),
|
||||||
|
passwords: [password1, password2],
|
||||||
|
armor: false
|
||||||
|
};
|
||||||
|
var decOpt = {
|
||||||
|
sessionKey: password2,
|
||||||
|
format: 'binary'
|
||||||
|
};
|
||||||
|
openpgp.encrypt(encOpt).then(function(encrypted) {
|
||||||
|
decOpt.message = encrypted.message;
|
||||||
|
return openpgp.decrypt(decOpt);
|
||||||
|
}).then(function(decrypted) {
|
||||||
|
if (openpgp.getWorker()) {
|
||||||
|
expect(encOpt.data.byteLength).to.equal(0); // transfered buffer should be empty
|
||||||
|
}
|
||||||
|
expect(decrypted.data).to.deep.equal(new Uint8Array([0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01]));
|
||||||
|
openpgp.config.zeroCopy = false;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user