Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Commit

Permalink
fix(node): patch crypto as macroTask and add test cases for crypto, r…
Browse files Browse the repository at this point in the history
…emove http patch (#612)

* patch crypto as macroTask and add test cases for crypto

* remove http patch, because it has been patched by EventEmitter
  • Loading branch information
JiaLiPassion authored and mhevery committed Jan 23, 2017
1 parent a58cde4 commit c238aa4
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 44 deletions.
58 changes: 14 additions & 44 deletions lib/node/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import './events';
import './fs';

import {patchTimer} from '../common/timers';
import {patchMethod} from '../common/utils';
import {patchMacroTask, patchMethod} from '../common/utils';

const set = 'set';
const clear = 'clear';
Expand Down Expand Up @@ -40,50 +40,20 @@ try {
} catch (err) {
}

// TODO(gdi2290): implement a better way to patch these methods
// use the generic patchMacroTask to patch crypto
if (crypto) {
let nativeRandomBytes = crypto.randomBytes;
crypto.randomBytes = function randomBytesZone(size: number, callback?: Function) {
if (!callback) {
return nativeRandomBytes(size);
} else {
let zone = Zone.current;
const source = crypto.constructor.name + '.randomBytes';
return nativeRandomBytes(size, zone.wrap(callback, source));
}
}.bind(crypto);

let nativePbkdf2 = crypto.pbkdf2;
crypto.pbkdf2 = function pbkdf2Zone(...args: any[]) {
let fn = args[args.length - 1];
if (typeof fn === 'function') {
let zone = Zone.current;
const source = crypto.constructor.name + '.pbkdf2';
args[args.length - 1] = zone.wrap(fn, source);
return nativePbkdf2(...args);
} else {
return nativePbkdf2(...args);
}
}.bind(crypto);
}

// HTTP Client
let httpClient;
try {
httpClient = require('_http_client');
} catch (err) {
}

if (httpClient && httpClient.ClientRequest) {
let ClientRequest = httpClient.ClientRequest.bind(httpClient);
httpClient.ClientRequest = function(options: any, callback?: Function) {
if (!callback) {
return new ClientRequest(options);
} else {
let zone = Zone.current;
return new ClientRequest(options, zone.wrap(callback, 'http.ClientRequest'));
}
};
const methodNames = ['randomBytes', 'pbkdf2'];
methodNames.forEach(name => {
patchMacroTask(crypto, name, (self: any, args: any[]) => {
return {
name: 'crypto.' + name,
args: args,
callbackIndex:
(args.length > 0 && typeof args[args.length - 1] === 'function') ? args.length - 1 : -1,
target: crypto
};
});
});
}

function patchNextTick() {
Expand Down
65 changes: 65 additions & 0 deletions test/node/crypto.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
describe('crypto test', () => {
let crypto = null;

try {
crypto = require('crypto');
} catch (err) {
}

it('crypto randomBytes method should be patched as tasks', (done) => {
if (!crypto) {
done();
return;
}
const zoneASpec = {
name: 'A',
onScheduleTask: (delegate, currentZone, targetZone, task): Task => {
return delegate.scheduleTask(targetZone, task);
}
};
const zoneA = Zone.current.fork(zoneASpec);
spyOn(zoneASpec, 'onScheduleTask').and.callThrough();
zoneA.run(() => {
crypto.randomBytes(256, (err, buf) => {
expect(err).toBeFalsy();
expect(zoneASpec.onScheduleTask).toHaveBeenCalled();
expect(buf.length).toBe(256);
expect(Zone.current.name).toEqual('A');
done();
});
});
});

it('crypto pbkdf2 method should be patched as tasks', (done) => {
if (!crypto) {
done();
return;
}
const zoneASpec = {
name: 'A',
onScheduleTask: (delegate, currentZone, targetZone, task): Task => {
return delegate.scheduleTask(targetZone, task);
}
};
const zoneA = Zone.current.fork(zoneASpec);
spyOn(zoneASpec, 'onScheduleTask').and.callThrough();
zoneA.run(() => {
crypto.pbkdf2('secret', 'salt', 100000, 512, 'sha512', (err, key) => {
expect(err).toBeFalsy();
expect(zoneASpec.onScheduleTask).toHaveBeenCalled();
expect(key.toString('hex'))
.toEqual(
'3745e482c6e0ade35da10139e797157f4a5da669dad7d5da88ef87e47471cc47ed941c7ad618e827304f083f8707f12b7cfdd5f489b782f10cc269e3c08d59ae04919ee902c99dba309cde75569fbe8e6d5c341d6f2576f6618c589e77911a261ee964e242797e64aeca9a134de5ced37fe2521d35d87303edb55a844c8cf11e3b42b18dbd7add0739ea9b172dc3810f911396fa3956f499415db35b79488d74926cdc0c15c3910bf2e4918f5a8efd7de3d4c314bace50c7a95150339eccd32dda2e15d961ea2c91eddd8b03110135a72b3562f189c2d15568854f9a1844cfa62fb77214f2810a2277fd21be95a794cde78e0fe5267a2c1b0894c7729fc4be378156aeb1cff8a215bb4df12312ba676fe2f270dfc3e2b54d8f9c74dfb531530042a09b226fafbcef45368a1ec75f9224a80f2280f75258ff74a2b9a864d857ede49af6a23af837a1f502a6c32e3537402280bef200d847d8fee42649e6d9a00df952ab2fbefc84ba8927f73137fdfbea81f86088edd4cf329edf3f6982429797143cbd43128777c2da269fadd55d18c7921308c7ad7a5bb85ef8d614e2e8461ea3b7fc2edcf72b85da6828a4198c46000953afb1f3a19ecac0df0d660848a0f89ed3d0e0a82115347c9918bdf16fad479c1de16a6b9798437622acff245e6cf80c9ee9d56cada8523ebb6ff348c73c836e5828761f8dda1dd5ab1633caa39b34');
expect(Zone.current.name).toEqual('A');
done();
});
});
});
});
35 changes: 35 additions & 0 deletions test/node/http.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
const http = require('http');
describe('http test', () => {
it('http.request should be patched as eventTask', (done) => {
const server = http.createServer((req, res) => {
res.end();
});
server.listen(9999, () => {
const zoneASpec = {
name: 'A',
onScheduleTask: (delegate, currentZone, targetZone, task): Task => {
return delegate.scheduleTask(targetZone, task);
}
};
const zoneA = Zone.current.fork(zoneASpec);
spyOn(zoneASpec, 'onScheduleTask').and.callThrough();
zoneA.run(() => {
const req = http.request({hostname: 'localhost', port: '9999', method: 'GET'}, (res) => {
expect(Zone.current.name).toEqual('A');
expect(zoneASpec.onScheduleTask).toHaveBeenCalled();
server.close(() => {
done();
});
});
req.end();
});
});
});
});
2 changes: 2 additions & 0 deletions test/node_tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ import './node/events.spec';
import './node/fs.spec';
import './node/process.spec';
import './node/Error.spec';
import './node/crypto.spec';
import './node/http.spec';

0 comments on commit c238aa4

Please sign in to comment.