Support transferable objects in web worker for zero copy support

This commit is contained in:
Tankred Hase 2016-02-09 17:01:48 +07:00
parent 89df70cbe0
commit ab68d4b997
5 changed files with 65 additions and 5 deletions

View File

@ -41,6 +41,7 @@ export default {
ignore_mdc_error: false, // fail on decrypt if message is not integrity protected
rsa_blinding: true,
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,
show_version: true,
show_comment: true,

View File

@ -54,6 +54,35 @@ export default {
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) {
var n = 0;

View File

@ -26,6 +26,7 @@
'use strict';
import util from '../util.js';
import crypto from '../crypto';
import packet from '../packet';
import * as key from '../key.js';
@ -100,7 +101,7 @@ AsyncProxy.prototype.onMessage = function(event) {
*/
AsyncProxy.prototype.seedRandom = function(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) {
return new Promise((resolve, reject) => {
// 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
this.tasks.push({ resolve: data => resolve(parseClonedPackets(data, method)), reject });

View File

@ -163,7 +163,7 @@ function clonePackets(data) {
function response(event) {
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));
}

View File

@ -335,7 +335,7 @@ describe('OpenPGP.js public api tests', function() {
var password1 = 'I am a password';
var password2 = 'I am another password';
var privateKey, publicKey;
var privateKey, publicKey, zeroCopyVal;
beforeEach(function() {
publicKey = openpgp.key.readArmored(pub_key);
@ -344,6 +344,11 @@ describe('OpenPGP.js public api tests', function() {
privateKey = openpgp.key.readArmored(priv_key);
expect(privateKey.keys).to.have.length(1);
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 () {
@ -608,6 +613,30 @@ describe('OpenPGP.js public api tests', function() {
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();
});
});
});
}