index.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. 'use strict';
  2. if (process.addAsyncListener) throw new Error("Don't require polyfill unless needed");
  3. var shimmer = require('shimmer')
  4. , semver = require('semver')
  5. , wrap = shimmer.wrap
  6. , massWrap = shimmer.massWrap
  7. , wrapCallback = require('./glue.js')
  8. , util = require('util')
  9. ;
  10. var v6plus = semver.gte(process.version, '6.0.0');
  11. var v7plus = semver.gte(process.version, '7.0.0');
  12. var v8plus = semver.gte(process.version, '8.0.0');
  13. var v11plus = semver.gte(process.version, '11.0.0');
  14. var net = require('net');
  15. // From Node.js v7.0.0, net._normalizeConnectArgs have been renamed net._normalizeArgs
  16. if (v7plus && !net._normalizeArgs) {
  17. // a polyfill in our polyfill etc so forth -- taken from node master on 2017/03/09
  18. net._normalizeArgs = function (args) {
  19. if (args.length === 0) {
  20. return [{}, null];
  21. }
  22. var arg0 = args[0];
  23. var options = {};
  24. if (typeof arg0 === 'object' && arg0 !== null) {
  25. // (options[...][, cb])
  26. options = arg0;
  27. } else if (isPipeName(arg0)) {
  28. // (path[...][, cb])
  29. options.path = arg0;
  30. } else {
  31. // ([port][, host][...][, cb])
  32. options.port = arg0;
  33. if (args.length > 1 && typeof args[1] === 'string') {
  34. options.host = args[1];
  35. }
  36. }
  37. var cb = args[args.length - 1];
  38. if (typeof cb !== 'function')
  39. return [options, null];
  40. else
  41. return [options, cb];
  42. }
  43. } else if (!v7plus && !net._normalizeConnectArgs) {
  44. // a polyfill in our polyfill etc so forth -- taken from node master on 2013/10/30
  45. net._normalizeConnectArgs = function (args) {
  46. var options = {};
  47. function toNumber(x) { return (x = Number(x)) >= 0 ? x : false; }
  48. if (typeof args[0] === 'object' && args[0] !== null) {
  49. // connect(options, [cb])
  50. options = args[0];
  51. }
  52. else if (typeof args[0] === 'string' && toNumber(args[0]) === false) {
  53. // connect(path, [cb]);
  54. options.path = args[0];
  55. }
  56. else {
  57. // connect(port, [host], [cb])
  58. options.port = args[0];
  59. if (typeof args[1] === 'string') {
  60. options.host = args[1];
  61. }
  62. }
  63. var cb = args[args.length - 1];
  64. return typeof cb === 'function' ? [options, cb] : [options];
  65. };
  66. }
  67. // In https://github.com/nodejs/node/pull/11796 `_listen2` was renamed
  68. // `_setUpListenHandle`. It's still aliased as `_listen2`, and currently the
  69. // Node internals still call the alias - but who knows for how long. So better
  70. // make sure we use the new name instead if available.
  71. if ('_setUpListenHandle' in net.Server.prototype) {
  72. wrap(net.Server.prototype, '_setUpListenHandle', wrapSetUpListenHandle);
  73. } else {
  74. wrap(net.Server.prototype, '_listen2', wrapSetUpListenHandle);
  75. }
  76. function wrapSetUpListenHandle(original) {
  77. return function () {
  78. this.on('connection', function (socket) {
  79. if (socket._handle) {
  80. socket._handle.onread = wrapCallback(socket._handle.onread);
  81. }
  82. });
  83. try {
  84. return original.apply(this, arguments);
  85. }
  86. finally {
  87. // the handle will only not be set in cases where there has been an error
  88. if (this._handle && this._handle.onconnection) {
  89. this._handle.onconnection = wrapCallback(this._handle.onconnection);
  90. }
  91. }
  92. };
  93. }
  94. function patchOnRead(ctx) {
  95. if (ctx && ctx._handle) {
  96. var handle = ctx._handle;
  97. if (!handle._originalOnread) {
  98. handle._originalOnread = handle.onread;
  99. }
  100. handle.onread = wrapCallback(handle._originalOnread);
  101. }
  102. }
  103. wrap(net.Socket.prototype, 'connect', function (original) {
  104. return function () {
  105. var args;
  106. // Node core uses an internal Symbol here to guard against the edge-case
  107. // where the user accidentally passes in an array. As we don't have access
  108. // to this Symbol we resort to this hack where we just detect if there is a
  109. // symbol or not. Checking for the number of Symbols is by no means a fool
  110. // proof solution, but it catches the most basic cases.
  111. if (v8plus &&
  112. Array.isArray(arguments[0]) &&
  113. Object.getOwnPropertySymbols(arguments[0]).length > 0) {
  114. // already normalized
  115. args = arguments[0];
  116. } else {
  117. // From Node.js v7.0.0, net._normalizeConnectArgs have been renamed net._normalizeArgs
  118. args = v7plus
  119. ? net._normalizeArgs(arguments)
  120. : net._normalizeConnectArgs(arguments);
  121. }
  122. if (args[1]) args[1] = wrapCallback(args[1]);
  123. var result = original.apply(this, args);
  124. patchOnRead(this);
  125. return result;
  126. };
  127. });
  128. var http = require('http');
  129. // NOTE: A rewrite occurred in 0.11 that changed the addRequest signature
  130. // from (req, host, port, localAddress) to (req, options)
  131. // Here, I use the longer signature to maintain 0.10 support, even though
  132. // the rest of the arguments aren't actually used
  133. wrap(http.Agent.prototype, 'addRequest', function (original) {
  134. return function (req) {
  135. var onSocket = req.onSocket;
  136. req.onSocket = wrapCallback(function (socket) {
  137. patchOnRead(socket);
  138. return onSocket.apply(this, arguments);
  139. });
  140. return original.apply(this, arguments);
  141. };
  142. });
  143. var childProcess = require('child_process');
  144. function wrapChildProcess(child) {
  145. if (Array.isArray(child.stdio)) {
  146. child.stdio.forEach(function (socket) {
  147. if (socket && socket._handle) {
  148. socket._handle.onread = wrapCallback(socket._handle.onread);
  149. wrap(socket._handle, 'close', activatorFirst);
  150. }
  151. });
  152. }
  153. if (child._handle) {
  154. child._handle.onexit = wrapCallback(child._handle.onexit);
  155. }
  156. }
  157. // iojs v2.0.0+
  158. if (childProcess.ChildProcess) {
  159. wrap(childProcess.ChildProcess.prototype, 'spawn', function (original) {
  160. return function () {
  161. var result = original.apply(this, arguments);
  162. wrapChildProcess(this);
  163. return result;
  164. };
  165. });
  166. } else {
  167. massWrap(childProcess, [
  168. 'execFile', // exec is implemented in terms of execFile
  169. 'fork',
  170. 'spawn'
  171. ], function (original) {
  172. return function () {
  173. var result = original.apply(this, arguments);
  174. wrapChildProcess(result);
  175. return result;
  176. };
  177. });
  178. }
  179. // need unwrapped nextTick for use within < 0.9 async error handling
  180. if (!process._fatalException) {
  181. process._originalNextTick = process.nextTick;
  182. }
  183. var processors = [];
  184. if (process._nextDomainTick) processors.push('_nextDomainTick');
  185. if (process._tickDomainCallback) processors.push('_tickDomainCallback');
  186. massWrap(
  187. process,
  188. processors,
  189. activator
  190. );
  191. wrap(process, 'nextTick', activatorFirst);
  192. var asynchronizers = [
  193. 'setTimeout',
  194. 'setInterval'
  195. ];
  196. if (global.setImmediate) asynchronizers.push('setImmediate');
  197. var timers = require('timers');
  198. var patchGlobalTimers = global.setTimeout === timers.setTimeout;
  199. massWrap(
  200. timers,
  201. asynchronizers,
  202. activatorFirst
  203. );
  204. if (patchGlobalTimers) {
  205. massWrap(
  206. global,
  207. asynchronizers,
  208. activatorFirst
  209. );
  210. }
  211. var dns = require('dns');
  212. massWrap(
  213. dns,
  214. [
  215. 'lookup',
  216. 'resolve',
  217. 'resolve4',
  218. 'resolve6',
  219. 'resolveCname',
  220. 'resolveMx',
  221. 'resolveNs',
  222. 'resolveTxt',
  223. 'resolveSrv',
  224. 'reverse'
  225. ],
  226. activator
  227. );
  228. if (dns.resolveNaptr) wrap(dns, 'resolveNaptr', activator);
  229. var fs = require('fs');
  230. massWrap(
  231. fs,
  232. [
  233. 'watch',
  234. 'rename',
  235. 'truncate',
  236. 'chown',
  237. 'fchown',
  238. 'chmod',
  239. 'fchmod',
  240. 'stat',
  241. 'lstat',
  242. 'fstat',
  243. 'link',
  244. 'symlink',
  245. 'readlink',
  246. 'realpath',
  247. 'unlink',
  248. 'rmdir',
  249. 'mkdir',
  250. 'readdir',
  251. 'close',
  252. 'open',
  253. 'utimes',
  254. 'futimes',
  255. 'fsync',
  256. 'write',
  257. 'read',
  258. 'readFile',
  259. 'writeFile',
  260. 'appendFile',
  261. 'watchFile',
  262. 'unwatchFile',
  263. "exists",
  264. ],
  265. activator
  266. );
  267. // only wrap lchown and lchmod on systems that have them.
  268. if (fs.lchown) wrap(fs, 'lchown', activator);
  269. if (fs.lchmod) wrap(fs, 'lchmod', activator);
  270. // only wrap ftruncate in versions of node that have it
  271. if (fs.ftruncate) wrap(fs, 'ftruncate', activator);
  272. // Wrap zlib streams
  273. var zlib;
  274. try { zlib = require('zlib'); } catch (err) { }
  275. if (zlib && zlib.Deflate && zlib.Deflate.prototype) {
  276. var proto = Object.getPrototypeOf(zlib.Deflate.prototype);
  277. if (proto._transform) {
  278. // streams2
  279. wrap(proto, "_transform", activator);
  280. }
  281. else if (proto.write && proto.flush && proto.end) {
  282. // plain ol' streams
  283. massWrap(
  284. proto,
  285. [
  286. 'write',
  287. 'flush',
  288. 'end'
  289. ],
  290. activator
  291. );
  292. }
  293. }
  294. // Wrap Crypto
  295. var crypto;
  296. try { crypto = require('crypto'); } catch (err) { }
  297. if (crypto) {
  298. var toWrap = [
  299. 'pbkdf2',
  300. 'randomBytes',
  301. ];
  302. if (!v11plus) {
  303. toWrap.push('pseudoRandomBytes');
  304. }
  305. massWrap(crypto, toWrap, activator);
  306. }
  307. // It is unlikely that any userspace promise implementations have a native
  308. // implementation of both Promise and Promise.toString.
  309. var instrumentPromise = !!global.Promise &&
  310. Promise.toString() === 'function Promise() { [native code] }' &&
  311. Promise.toString.toString() === 'function toString() { [native code] }';
  312. // Check that global Promise is native
  313. if (instrumentPromise) {
  314. // shoult not use any methods that have already been wrapped
  315. var promiseListener = process.addAsyncListener({
  316. create: function create() {
  317. instrumentPromise = false;
  318. }
  319. });
  320. // should not resolve synchronously
  321. global.Promise.resolve(true).then(function notSync() {
  322. instrumentPromise = false;
  323. });
  324. process.removeAsyncListener(promiseListener);
  325. }
  326. /*
  327. * Native promises use the microtask queue to make all callbacks run
  328. * asynchronously to avoid Zalgo issues. Since the microtask queue is not
  329. * exposed externally, promises need to be modified in a fairly invasive and
  330. * complex way.
  331. *
  332. * The async boundary in promises that must be patched is between the
  333. * fulfillment of the promise and the execution of any callback that is waiting
  334. * for that fulfillment to happen. This means that we need to trigger a create
  335. * when resolve or reject is called and trigger before, after and error handlers
  336. * around the callback execution. There may be multiple callbacks for each
  337. * fulfilled promise, so handlers will behave similar to setInterval where
  338. * there may be multiple before after and error calls for each create call.
  339. *
  340. * async-listener monkeypatching has one basic entry point: `wrapCallback`.
  341. * `wrapCallback` should be called when create should be triggered and be
  342. * passed a function to wrap, which will execute the body of the async work.
  343. * The resolve and reject calls can be modified fairly easily to call
  344. * `wrapCallback`, but at the time of resolve and reject all the work to be done
  345. * on fulfillment may not be defined, since a call to then, chain or fetch can
  346. * be made even after the promise has been fulfilled. To get around this, we
  347. * create a placeholder function which will call a function passed into it,
  348. * since the call to the main work is being made from within the wrapped
  349. * function, async-listener will work correctly.
  350. *
  351. * There is another complication with monkeypatching Promises. Calls to then,
  352. * chain and catch each create new Promises that are fulfilled internally in
  353. * different ways depending on the return value of the callback. When the
  354. * callback return a Promise, the new Promise is resolved asynchronously after
  355. * the returned Promise has been also been resolved. When something other than
  356. * a promise is resolved the resolve call for the new Promise is put in the
  357. * microtask queue and asynchronously resolved.
  358. *
  359. * Then must be wrapped so that its returned promise has a wrapper that can be
  360. * used to invoke further continuations. This wrapper cannot be created until
  361. * after the callback has run, since the callback may return either a promise
  362. * or another value. Fortunately we already have a wrapper function around the
  363. * callback we can use (the wrapper created by resolve or reject).
  364. *
  365. * By adding an additional argument to this wrapper, we can pass in the
  366. * returned promise so it can have its own wrapper appended. the wrapper
  367. * function can the call the callback, and take action based on the return
  368. * value. If a promise is returned, the new Promise can proxy the returned
  369. * Promise's wrapper (this wrapper may not exist yet, but will by the time the
  370. * wrapper needs to be invoked). Otherwise, a new wrapper can be create the
  371. * same way as in resolve and reject. Since this wrapper is created
  372. * synchronously within another wrapper, it will properly appear as a
  373. * continuation from within the callback.
  374. */
  375. if (instrumentPromise) {
  376. wrapPromise();
  377. }
  378. function wrapPromise() {
  379. var Promise = global.Promise;
  380. // Updates to this class should also be applied to the the ES6 version
  381. // in es6-wrapped-promise.js.
  382. function wrappedPromise(executor) {
  383. if (!(this instanceof wrappedPromise)) {
  384. return Promise(executor);
  385. }
  386. if (typeof executor !== 'function') {
  387. return new Promise(executor);
  388. }
  389. var context, args;
  390. var promise = new Promise(wrappedExecutor);
  391. promise.__proto__ = wrappedPromise.prototype;
  392. try {
  393. executor.apply(context, args);
  394. } catch (err) {
  395. args[1](err);
  396. }
  397. return promise;
  398. function wrappedExecutor(resolve, reject) {
  399. context = this;
  400. args = [wrappedResolve, wrappedReject];
  401. // These wrappers create a function that can be passed a function and an argument to
  402. // call as a continuation from the resolve or reject.
  403. function wrappedResolve(val) {
  404. ensureAslWrapper(promise, false);
  405. return resolve(val);
  406. }
  407. function wrappedReject(val) {
  408. ensureAslWrapper(promise, false);
  409. return reject(val);
  410. }
  411. }
  412. }
  413. util.inherits(wrappedPromise, Promise);
  414. wrap(Promise.prototype, 'then', wrapThen);
  415. // Node.js <v7 only, alias for .then
  416. if (Promise.prototype.chain) {
  417. wrap(Promise.prototype, 'chain', wrapThen);
  418. }
  419. if (v6plus) {
  420. global.Promise = require('./es6-wrapped-promise.js')(Promise, ensureAslWrapper);
  421. } else {
  422. var PromiseFunctions = [
  423. 'all',
  424. 'race',
  425. 'reject',
  426. 'resolve',
  427. 'accept', // Node.js <v7 only
  428. 'defer' // Node.js <v7 only
  429. ];
  430. PromiseFunctions.forEach(function(key) {
  431. // don't break `in` by creating a key for undefined entries
  432. if (typeof Promise[key] === 'function') {
  433. wrappedPromise[key] = Promise[key];
  434. }
  435. });
  436. global.Promise = wrappedPromise
  437. }
  438. function ensureAslWrapper(promise, overwrite) {
  439. if (!promise.__asl_wrapper || overwrite) {
  440. promise.__asl_wrapper = wrapCallback(propagateAslWrapper);
  441. }
  442. }
  443. function propagateAslWrapper(ctx, fn, result, next) {
  444. var nextResult;
  445. try {
  446. nextResult = fn.call(ctx, result);
  447. return {returnVal: nextResult, error: false}
  448. } catch (err) {
  449. return {errorVal: err, error: true}
  450. } finally {
  451. // Wrap any resulting futures as continuations.
  452. if (nextResult instanceof Promise) {
  453. next.__asl_wrapper = function proxyWrapper() {
  454. var aslWrapper = nextResult.__asl_wrapper || propagateAslWrapper;
  455. return aslWrapper.apply(this, arguments);
  456. }
  457. } else {
  458. ensureAslWrapper(next, true);
  459. }
  460. }
  461. }
  462. function wrapThen(original) {
  463. return function wrappedThen() {
  464. var promise = this;
  465. var next = original.apply(promise, Array.prototype.map.call(arguments, bind));
  466. next.__asl_wrapper = function proxyWrapper(ctx, fn, val, last) {
  467. if (promise.__asl_wrapper) {
  468. promise.__asl_wrapper(ctx, function () {}, null, next);
  469. return next.__asl_wrapper(ctx, fn, val, last);
  470. }
  471. return propagateAslWrapper(ctx, fn, val, last);
  472. }
  473. return next;
  474. // wrap callbacks (success, error) so that the callbacks will be called as a
  475. // continuations of the resolve or reject call using the __asl_wrapper created above.
  476. function bind(fn) {
  477. if (typeof fn !== 'function') return fn;
  478. return wrapCallback(function (val) {
  479. var result = (promise.__asl_wrapper || propagateAslWrapper)(this, fn, val, next);
  480. if (result.error) {
  481. throw result.errorVal
  482. } else {
  483. return result.returnVal
  484. }
  485. });
  486. }
  487. }
  488. }
  489. }
  490. // Shim activator for functions that have callback last
  491. function activator(fn) {
  492. var fallback = function () {
  493. var args;
  494. var cbIdx = arguments.length - 1;
  495. if (typeof arguments[cbIdx] === "function") {
  496. args = Array(arguments.length)
  497. for (var i = 0; i < arguments.length - 1; i++) {
  498. args[i] = arguments[i];
  499. }
  500. args[cbIdx] = wrapCallback(arguments[cbIdx]);
  501. }
  502. return fn.apply(this, args || arguments);
  503. };
  504. // Preserve function length for small arg count functions.
  505. switch (fn.length) {
  506. case 1:
  507. return function (cb) {
  508. if (arguments.length !== 1) return fallback.apply(this, arguments);
  509. if (typeof cb === "function") cb = wrapCallback(cb);
  510. return fn.call(this, cb);
  511. };
  512. case 2:
  513. return function (a, cb) {
  514. if (arguments.length !== 2) return fallback.apply(this, arguments);
  515. if (typeof cb === "function") cb = wrapCallback(cb);
  516. return fn.call(this, a, cb);
  517. };
  518. case 3:
  519. return function (a, b, cb) {
  520. if (arguments.length !== 3) return fallback.apply(this, arguments);
  521. if (typeof cb === "function") cb = wrapCallback(cb);
  522. return fn.call(this, a, b, cb);
  523. };
  524. case 4:
  525. return function (a, b, c, cb) {
  526. if (arguments.length !== 4) return fallback.apply(this, arguments);
  527. if (typeof cb === "function") cb = wrapCallback(cb);
  528. return fn.call(this, a, b, c, cb);
  529. };
  530. case 5:
  531. return function (a, b, c, d, cb) {
  532. if (arguments.length !== 5) return fallback.apply(this, arguments);
  533. if (typeof cb === "function") cb = wrapCallback(cb);
  534. return fn.call(this, a, b, c, d, cb);
  535. };
  536. case 6:
  537. return function (a, b, c, d, e, cb) {
  538. if (arguments.length !== 6) return fallback.apply(this, arguments);
  539. if (typeof cb === "function") cb = wrapCallback(cb);
  540. return fn.call(this, a, b, c, d, e, cb);
  541. };
  542. default:
  543. return fallback;
  544. }
  545. }
  546. // Shim activator for functions that have callback first
  547. function activatorFirst(fn) {
  548. var fallback = function () {
  549. var args;
  550. if (typeof arguments[0] === "function") {
  551. args = Array(arguments.length)
  552. args[0] = wrapCallback(arguments[0]);
  553. for (var i = 1; i < arguments.length; i++) {
  554. args[i] = arguments[i];
  555. }
  556. }
  557. return fn.apply(this, args || arguments);
  558. };
  559. // Preserve function length for small arg count functions.
  560. switch (fn.length) {
  561. case 1:
  562. return function (cb) {
  563. if (arguments.length !== 1) return fallback.apply(this, arguments);
  564. if (typeof cb === "function") cb = wrapCallback(cb);
  565. return fn.call(this, cb);
  566. };
  567. case 2:
  568. return function (cb, a) {
  569. if (arguments.length !== 2) return fallback.apply(this, arguments);
  570. if (typeof cb === "function") cb = wrapCallback(cb);
  571. return fn.call(this, cb, a);
  572. };
  573. case 3:
  574. return function (cb, a, b) {
  575. if (arguments.length !== 3) return fallback.apply(this, arguments);
  576. if (typeof cb === "function") cb = wrapCallback(cb);
  577. return fn.call(this, cb, a, b);
  578. };
  579. case 4:
  580. return function (cb, a, b, c) {
  581. if (arguments.length !== 4) return fallback.apply(this, arguments);
  582. if (typeof cb === "function") cb = wrapCallback(cb);
  583. return fn.call(this, cb, a, b, c);
  584. };
  585. case 5:
  586. return function (cb, a, b, c, d) {
  587. if (arguments.length !== 5) return fallback.apply(this, arguments);
  588. if (typeof cb === "function") cb = wrapCallback(cb);
  589. return fn.call(this, cb, a, b, c, d);
  590. };
  591. case 6:
  592. return function (cb, a, b, c, d, e) {
  593. if (arguments.length !== 6) return fallback.apply(this, arguments);
  594. if (typeof cb === "function") cb = wrapCallback(cb);
  595. return fn.call(this, cb, a, b, c, d, e);
  596. };
  597. default:
  598. return fallback;
  599. }
  600. }
  601. // taken from node master on 2017/03/09
  602. function toNumber(x) {
  603. return (x = Number(x)) >= 0 ? x : false;
  604. }
  605. // taken from node master on 2017/03/09
  606. function isPipeName(s) {
  607. return typeof s === 'string' && toNumber(s) === false;
  608. }