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

Commit 9e81037

Browse files
JiaLiPassionmhevery
authored andcommitted
fix(node): patch crypto as macroTask and add test cases for crypto, remove http patch (#612)
* patch crypto as macroTask and add test cases for crypto * remove http patch, because it has been patched by EventEmitter
1 parent 7665e5a commit 9e81037

File tree

4 files changed

+116
-44
lines changed

4 files changed

+116
-44
lines changed

Diff for: lib/node/node.ts

+14-44
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import './events';
1111
import './fs';
1212

1313
import {patchTimer} from '../common/timers';
14-
import {patchMethod} from '../common/utils';
14+
import {patchMacroTask, patchMethod} from '../common/utils';
1515

1616
const set = 'set';
1717
const clear = 'clear';
@@ -40,50 +40,20 @@ try {
4040
} catch (err) {
4141
}
4242

43-
// TODO(gdi2290): implement a better way to patch these methods
43+
// use the generic patchMacroTask to patch crypto
4444
if (crypto) {
45-
let nativeRandomBytes = crypto.randomBytes;
46-
crypto.randomBytes = function randomBytesZone(size: number, callback?: Function) {
47-
if (!callback) {
48-
return nativeRandomBytes(size);
49-
} else {
50-
let zone = Zone.current;
51-
const source = crypto.constructor.name + '.randomBytes';
52-
return nativeRandomBytes(size, zone.wrap(callback, source));
53-
}
54-
}.bind(crypto);
55-
56-
let nativePbkdf2 = crypto.pbkdf2;
57-
crypto.pbkdf2 = function pbkdf2Zone(...args: any[]) {
58-
let fn = args[args.length - 1];
59-
if (typeof fn === 'function') {
60-
let zone = Zone.current;
61-
const source = crypto.constructor.name + '.pbkdf2';
62-
args[args.length - 1] = zone.wrap(fn, source);
63-
return nativePbkdf2(...args);
64-
} else {
65-
return nativePbkdf2(...args);
66-
}
67-
}.bind(crypto);
68-
}
69-
70-
// HTTP Client
71-
let httpClient;
72-
try {
73-
httpClient = require('_http_client');
74-
} catch (err) {
75-
}
76-
77-
if (httpClient && httpClient.ClientRequest) {
78-
let ClientRequest = httpClient.ClientRequest.bind(httpClient);
79-
httpClient.ClientRequest = function(options: any, callback?: Function) {
80-
if (!callback) {
81-
return new ClientRequest(options);
82-
} else {
83-
let zone = Zone.current;
84-
return new ClientRequest(options, zone.wrap(callback, 'http.ClientRequest'));
85-
}
86-
};
45+
const methodNames = ['randomBytes', 'pbkdf2'];
46+
methodNames.forEach(name => {
47+
patchMacroTask(crypto, name, (self: any, args: any[]) => {
48+
return {
49+
name: 'crypto.' + name,
50+
args: args,
51+
callbackIndex:
52+
(args.length > 0 && typeof args[args.length - 1] === 'function') ? args.length - 1 : -1,
53+
target: crypto
54+
};
55+
});
56+
});
8757
}
8858

8959
function patchNextTick() {

Diff for: test/node/crypto.spec.ts

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
describe('crypto test', () => {
9+
let crypto = null;
10+
11+
try {
12+
crypto = require('crypto');
13+
} catch (err) {
14+
}
15+
16+
it('crypto randomBytes method should be patched as tasks', (done) => {
17+
if (!crypto) {
18+
done();
19+
return;
20+
}
21+
const zoneASpec = {
22+
name: 'A',
23+
onScheduleTask: (delegate, currentZone, targetZone, task): Task => {
24+
return delegate.scheduleTask(targetZone, task);
25+
}
26+
};
27+
const zoneA = Zone.current.fork(zoneASpec);
28+
spyOn(zoneASpec, 'onScheduleTask').and.callThrough();
29+
zoneA.run(() => {
30+
crypto.randomBytes(256, (err, buf) => {
31+
expect(err).toBeFalsy();
32+
expect(zoneASpec.onScheduleTask).toHaveBeenCalled();
33+
expect(buf.length).toBe(256);
34+
expect(Zone.current.name).toEqual('A');
35+
done();
36+
});
37+
});
38+
});
39+
40+
it('crypto pbkdf2 method should be patched as tasks', (done) => {
41+
if (!crypto) {
42+
done();
43+
return;
44+
}
45+
const zoneASpec = {
46+
name: 'A',
47+
onScheduleTask: (delegate, currentZone, targetZone, task): Task => {
48+
return delegate.scheduleTask(targetZone, task);
49+
}
50+
};
51+
const zoneA = Zone.current.fork(zoneASpec);
52+
spyOn(zoneASpec, 'onScheduleTask').and.callThrough();
53+
zoneA.run(() => {
54+
crypto.pbkdf2('secret', 'salt', 100000, 512, 'sha512', (err, key) => {
55+
expect(err).toBeFalsy();
56+
expect(zoneASpec.onScheduleTask).toHaveBeenCalled();
57+
expect(key.toString('hex'))
58+
.toEqual(
59+
'3745e482c6e0ade35da10139e797157f4a5da669dad7d5da88ef87e47471cc47ed941c7ad618e827304f083f8707f12b7cfdd5f489b782f10cc269e3c08d59ae04919ee902c99dba309cde75569fbe8e6d5c341d6f2576f6618c589e77911a261ee964e242797e64aeca9a134de5ced37fe2521d35d87303edb55a844c8cf11e3b42b18dbd7add0739ea9b172dc3810f911396fa3956f499415db35b79488d74926cdc0c15c3910bf2e4918f5a8efd7de3d4c314bace50c7a95150339eccd32dda2e15d961ea2c91eddd8b03110135a72b3562f189c2d15568854f9a1844cfa62fb77214f2810a2277fd21be95a794cde78e0fe5267a2c1b0894c7729fc4be378156aeb1cff8a215bb4df12312ba676fe2f270dfc3e2b54d8f9c74dfb531530042a09b226fafbcef45368a1ec75f9224a80f2280f75258ff74a2b9a864d857ede49af6a23af837a1f502a6c32e3537402280bef200d847d8fee42649e6d9a00df952ab2fbefc84ba8927f73137fdfbea81f86088edd4cf329edf3f6982429797143cbd43128777c2da269fadd55d18c7921308c7ad7a5bb85ef8d614e2e8461ea3b7fc2edcf72b85da6828a4198c46000953afb1f3a19ecac0df0d660848a0f89ed3d0e0a82115347c9918bdf16fad479c1de16a6b9798437622acff245e6cf80c9ee9d56cada8523ebb6ff348c73c836e5828761f8dda1dd5ab1633caa39b34');
60+
expect(Zone.current.name).toEqual('A');
61+
done();
62+
});
63+
});
64+
});
65+
});

Diff for: test/node/http.spec.ts

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
const http = require('http');
9+
describe('http test', () => {
10+
it('http.request should be patched as eventTask', (done) => {
11+
const server = http.createServer((req, res) => {
12+
res.end();
13+
});
14+
server.listen(9999, () => {
15+
const zoneASpec = {
16+
name: 'A',
17+
onScheduleTask: (delegate, currentZone, targetZone, task): Task => {
18+
return delegate.scheduleTask(targetZone, task);
19+
}
20+
};
21+
const zoneA = Zone.current.fork(zoneASpec);
22+
spyOn(zoneASpec, 'onScheduleTask').and.callThrough();
23+
zoneA.run(() => {
24+
const req = http.request({hostname: 'localhost', port: '9999', method: 'GET'}, (res) => {
25+
expect(Zone.current.name).toEqual('A');
26+
expect(zoneASpec.onScheduleTask).toHaveBeenCalled();
27+
server.close(() => {
28+
done();
29+
});
30+
});
31+
req.end();
32+
});
33+
});
34+
});
35+
});

Diff for: test/node_tests.ts

+2
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ import './node/events.spec';
1010
import './node/fs.spec';
1111
import './node/process.spec';
1212
import './node/Error.spec';
13+
import './node/crypto.spec';
14+
import './node/http.spec';

0 commit comments

Comments
 (0)