11cb0ef41Sopenharmony_ci// Copyright Joyent, Inc. and other Node contributors. 21cb0ef41Sopenharmony_ci// 31cb0ef41Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a 41cb0ef41Sopenharmony_ci// copy of this software and associated documentation files (the 51cb0ef41Sopenharmony_ci// "Software"), to deal in the Software without restriction, including 61cb0ef41Sopenharmony_ci// without limitation the rights to use, copy, modify, merge, publish, 71cb0ef41Sopenharmony_ci// distribute, sublicense, and/or sell copies of the Software, and to permit 81cb0ef41Sopenharmony_ci// persons to whom the Software is furnished to do so, subject to the 91cb0ef41Sopenharmony_ci// following conditions: 101cb0ef41Sopenharmony_ci// 111cb0ef41Sopenharmony_ci// The above copyright notice and this permission notice shall be included 121cb0ef41Sopenharmony_ci// in all copies or substantial portions of the Software. 131cb0ef41Sopenharmony_ci// 141cb0ef41Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 151cb0ef41Sopenharmony_ci// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 161cb0ef41Sopenharmony_ci// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 171cb0ef41Sopenharmony_ci// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 181cb0ef41Sopenharmony_ci// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 191cb0ef41Sopenharmony_ci// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 201cb0ef41Sopenharmony_ci// USE OR OTHER DEALINGS IN THE SOFTWARE. 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci'use strict'; 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ci// WARNING: THIS MODULE IS PENDING DEPRECATION. 251cb0ef41Sopenharmony_ci// 261cb0ef41Sopenharmony_ci// No new pull requests targeting this module will be accepted 271cb0ef41Sopenharmony_ci// unless they address existing, critical bugs. 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ciconst { 301cb0ef41Sopenharmony_ci ArrayPrototypeEvery, 311cb0ef41Sopenharmony_ci ArrayPrototypeIndexOf, 321cb0ef41Sopenharmony_ci ArrayPrototypeLastIndexOf, 331cb0ef41Sopenharmony_ci ArrayPrototypePush, 341cb0ef41Sopenharmony_ci ArrayPrototypeSlice, 351cb0ef41Sopenharmony_ci ArrayPrototypeSplice, 361cb0ef41Sopenharmony_ci Error, 371cb0ef41Sopenharmony_ci FunctionPrototypeCall, 381cb0ef41Sopenharmony_ci ObjectDefineProperty, 391cb0ef41Sopenharmony_ci Promise, 401cb0ef41Sopenharmony_ci ReflectApply, 411cb0ef41Sopenharmony_ci SafeMap, 421cb0ef41Sopenharmony_ci SafeWeakMap, 431cb0ef41Sopenharmony_ci Symbol, 441cb0ef41Sopenharmony_ci} = primordials; 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ciconst EventEmitter = require('events'); 471cb0ef41Sopenharmony_ciconst { 481cb0ef41Sopenharmony_ci ERR_DOMAIN_CALLBACK_NOT_AVAILABLE, 491cb0ef41Sopenharmony_ci ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE, 501cb0ef41Sopenharmony_ci ERR_UNHANDLED_ERROR, 511cb0ef41Sopenharmony_ci} = require('internal/errors').codes; 521cb0ef41Sopenharmony_ciconst { createHook } = require('async_hooks'); 531cb0ef41Sopenharmony_ciconst { useDomainTrampoline } = require('internal/async_hooks'); 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_ci// TODO(addaleax): Use a non-internal solution for this. 561cb0ef41Sopenharmony_ciconst kWeak = Symbol('kWeak'); 571cb0ef41Sopenharmony_ciconst { WeakReference } = internalBinding('util'); 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ci// Overwrite process.domain with a getter/setter that will allow for more 601cb0ef41Sopenharmony_ci// effective optimizations 611cb0ef41Sopenharmony_ciconst _domain = [null]; 621cb0ef41Sopenharmony_ciObjectDefineProperty(process, 'domain', { 631cb0ef41Sopenharmony_ci __proto__: null, 641cb0ef41Sopenharmony_ci enumerable: true, 651cb0ef41Sopenharmony_ci get: function() { 661cb0ef41Sopenharmony_ci return _domain[0]; 671cb0ef41Sopenharmony_ci }, 681cb0ef41Sopenharmony_ci set: function(arg) { 691cb0ef41Sopenharmony_ci return _domain[0] = arg; 701cb0ef41Sopenharmony_ci }, 711cb0ef41Sopenharmony_ci}); 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_ciconst vmPromises = new SafeWeakMap(); 741cb0ef41Sopenharmony_ciconst pairing = new SafeMap(); 751cb0ef41Sopenharmony_ciconst asyncHook = createHook({ 761cb0ef41Sopenharmony_ci init(asyncId, type, triggerAsyncId, resource) { 771cb0ef41Sopenharmony_ci if (process.domain !== null && process.domain !== undefined) { 781cb0ef41Sopenharmony_ci // If this operation is created while in a domain, let's mark it 791cb0ef41Sopenharmony_ci pairing.set(asyncId, process.domain[kWeak]); 801cb0ef41Sopenharmony_ci // Promises from other contexts, such as with the VM module, should not 811cb0ef41Sopenharmony_ci // have a domain property as it can be used to escape the sandbox. 821cb0ef41Sopenharmony_ci if (type !== 'PROMISE' || resource instanceof Promise) { 831cb0ef41Sopenharmony_ci ObjectDefineProperty(resource, 'domain', { 841cb0ef41Sopenharmony_ci __proto__: null, 851cb0ef41Sopenharmony_ci configurable: true, 861cb0ef41Sopenharmony_ci enumerable: false, 871cb0ef41Sopenharmony_ci value: process.domain, 881cb0ef41Sopenharmony_ci writable: true, 891cb0ef41Sopenharmony_ci }); 901cb0ef41Sopenharmony_ci // Because promises from other contexts don't get a domain field, 911cb0ef41Sopenharmony_ci // the domain needs to be held alive another way. Stuffing it in a 921cb0ef41Sopenharmony_ci // weakmap connected to the promise lifetime can fix that. 931cb0ef41Sopenharmony_ci } else { 941cb0ef41Sopenharmony_ci vmPromises.set(resource, process.domain); 951cb0ef41Sopenharmony_ci } 961cb0ef41Sopenharmony_ci } 971cb0ef41Sopenharmony_ci }, 981cb0ef41Sopenharmony_ci before(asyncId) { 991cb0ef41Sopenharmony_ci const current = pairing.get(asyncId); 1001cb0ef41Sopenharmony_ci if (current !== undefined) { // Enter domain for this cb 1011cb0ef41Sopenharmony_ci // We will get the domain through current.get(), because the resource 1021cb0ef41Sopenharmony_ci // object's .domain property makes sure it is not garbage collected. 1031cb0ef41Sopenharmony_ci // However, we do need to make the reference to the domain non-weak, 1041cb0ef41Sopenharmony_ci // so that it cannot be garbage collected before the after() hook. 1051cb0ef41Sopenharmony_ci current.incRef(); 1061cb0ef41Sopenharmony_ci current.get().enter(); 1071cb0ef41Sopenharmony_ci } 1081cb0ef41Sopenharmony_ci }, 1091cb0ef41Sopenharmony_ci after(asyncId) { 1101cb0ef41Sopenharmony_ci const current = pairing.get(asyncId); 1111cb0ef41Sopenharmony_ci if (current !== undefined) { // Exit domain for this cb 1121cb0ef41Sopenharmony_ci const domain = current.get(); 1131cb0ef41Sopenharmony_ci current.decRef(); 1141cb0ef41Sopenharmony_ci domain.exit(); 1151cb0ef41Sopenharmony_ci } 1161cb0ef41Sopenharmony_ci }, 1171cb0ef41Sopenharmony_ci destroy(asyncId) { 1181cb0ef41Sopenharmony_ci pairing.delete(asyncId); // cleaning up 1191cb0ef41Sopenharmony_ci }, 1201cb0ef41Sopenharmony_ci}); 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci// When domains are in use, they claim full ownership of the 1231cb0ef41Sopenharmony_ci// uncaught exception capture callback. 1241cb0ef41Sopenharmony_ciif (process.hasUncaughtExceptionCaptureCallback()) { 1251cb0ef41Sopenharmony_ci throw new ERR_DOMAIN_CALLBACK_NOT_AVAILABLE(); 1261cb0ef41Sopenharmony_ci} 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ci// Get the stack trace at the point where `domain` was required. 1291cb0ef41Sopenharmony_ci// eslint-disable-next-line no-restricted-syntax 1301cb0ef41Sopenharmony_ciconst domainRequireStack = new Error('require(`domain`) at this point').stack; 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ciconst { setUncaughtExceptionCaptureCallback } = process; 1331cb0ef41Sopenharmony_ciprocess.setUncaughtExceptionCaptureCallback = function(fn) { 1341cb0ef41Sopenharmony_ci const err = new ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE(); 1351cb0ef41Sopenharmony_ci err.stack = err.stack + '\n' + '-'.repeat(40) + '\n' + domainRequireStack; 1361cb0ef41Sopenharmony_ci throw err; 1371cb0ef41Sopenharmony_ci}; 1381cb0ef41Sopenharmony_ci 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_cilet sendMakeCallbackDeprecation = false; 1411cb0ef41Sopenharmony_cifunction emitMakeCallbackDeprecation({ target, method }) { 1421cb0ef41Sopenharmony_ci if (!sendMakeCallbackDeprecation) { 1431cb0ef41Sopenharmony_ci process.emitWarning( 1441cb0ef41Sopenharmony_ci 'Using a domain property in MakeCallback is deprecated. Use the ' + 1451cb0ef41Sopenharmony_ci 'async_context variant of MakeCallback or the AsyncResource class ' + 1461cb0ef41Sopenharmony_ci 'instead. ' + 1471cb0ef41Sopenharmony_ci `(Triggered by calling ${method?.name || '<anonymous>'} ` + 1481cb0ef41Sopenharmony_ci `on ${target?.constructor?.name}.)`, 1491cb0ef41Sopenharmony_ci 'DeprecationWarning', 'DEP0097'); 1501cb0ef41Sopenharmony_ci sendMakeCallbackDeprecation = true; 1511cb0ef41Sopenharmony_ci } 1521cb0ef41Sopenharmony_ci} 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_cifunction topLevelDomainCallback(cb, ...args) { 1551cb0ef41Sopenharmony_ci const domain = this.domain; 1561cb0ef41Sopenharmony_ci if (exports.active && domain) 1571cb0ef41Sopenharmony_ci emitMakeCallbackDeprecation({ target: this, method: cb }); 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_ci if (domain) 1601cb0ef41Sopenharmony_ci domain.enter(); 1611cb0ef41Sopenharmony_ci const ret = ReflectApply(cb, this, args); 1621cb0ef41Sopenharmony_ci if (domain) 1631cb0ef41Sopenharmony_ci domain.exit(); 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_ci return ret; 1661cb0ef41Sopenharmony_ci} 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_ci// It's possible to enter one domain while already inside 1691cb0ef41Sopenharmony_ci// another one. The stack is each entered domain. 1701cb0ef41Sopenharmony_cilet stack = []; 1711cb0ef41Sopenharmony_ciexports._stack = stack; 1721cb0ef41Sopenharmony_ciuseDomainTrampoline(topLevelDomainCallback); 1731cb0ef41Sopenharmony_ci 1741cb0ef41Sopenharmony_cifunction updateExceptionCapture() { 1751cb0ef41Sopenharmony_ci if (ArrayPrototypeEvery(stack, 1761cb0ef41Sopenharmony_ci (domain) => domain.listenerCount('error') === 0)) { 1771cb0ef41Sopenharmony_ci setUncaughtExceptionCaptureCallback(null); 1781cb0ef41Sopenharmony_ci } else { 1791cb0ef41Sopenharmony_ci setUncaughtExceptionCaptureCallback(null); 1801cb0ef41Sopenharmony_ci setUncaughtExceptionCaptureCallback((er) => { 1811cb0ef41Sopenharmony_ci return process.domain._errorHandler(er); 1821cb0ef41Sopenharmony_ci }); 1831cb0ef41Sopenharmony_ci } 1841cb0ef41Sopenharmony_ci} 1851cb0ef41Sopenharmony_ci 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ciprocess.on('newListener', (name, listener) => { 1881cb0ef41Sopenharmony_ci if (name === 'uncaughtException' && 1891cb0ef41Sopenharmony_ci listener !== domainUncaughtExceptionClear) { 1901cb0ef41Sopenharmony_ci // Make sure the first listener for `uncaughtException` always clears 1911cb0ef41Sopenharmony_ci // the domain stack. 1921cb0ef41Sopenharmony_ci process.removeListener(name, domainUncaughtExceptionClear); 1931cb0ef41Sopenharmony_ci process.prependListener(name, domainUncaughtExceptionClear); 1941cb0ef41Sopenharmony_ci } 1951cb0ef41Sopenharmony_ci}); 1961cb0ef41Sopenharmony_ci 1971cb0ef41Sopenharmony_ciprocess.on('removeListener', (name, listener) => { 1981cb0ef41Sopenharmony_ci if (name === 'uncaughtException' && 1991cb0ef41Sopenharmony_ci listener !== domainUncaughtExceptionClear) { 2001cb0ef41Sopenharmony_ci // If the domain listener would be the only remaining one, remove it. 2011cb0ef41Sopenharmony_ci const listeners = process.listeners('uncaughtException'); 2021cb0ef41Sopenharmony_ci if (listeners.length === 1 && listeners[0] === domainUncaughtExceptionClear) 2031cb0ef41Sopenharmony_ci process.removeListener(name, domainUncaughtExceptionClear); 2041cb0ef41Sopenharmony_ci } 2051cb0ef41Sopenharmony_ci}); 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_cifunction domainUncaughtExceptionClear() { 2081cb0ef41Sopenharmony_ci stack.length = 0; 2091cb0ef41Sopenharmony_ci exports.active = process.domain = null; 2101cb0ef41Sopenharmony_ci updateExceptionCapture(); 2111cb0ef41Sopenharmony_ci} 2121cb0ef41Sopenharmony_ci 2131cb0ef41Sopenharmony_ci 2141cb0ef41Sopenharmony_ciclass Domain extends EventEmitter { 2151cb0ef41Sopenharmony_ci constructor() { 2161cb0ef41Sopenharmony_ci super(); 2171cb0ef41Sopenharmony_ci 2181cb0ef41Sopenharmony_ci this.members = []; 2191cb0ef41Sopenharmony_ci this[kWeak] = new WeakReference(this); 2201cb0ef41Sopenharmony_ci asyncHook.enable(); 2211cb0ef41Sopenharmony_ci 2221cb0ef41Sopenharmony_ci this.on('removeListener', updateExceptionCapture); 2231cb0ef41Sopenharmony_ci this.on('newListener', updateExceptionCapture); 2241cb0ef41Sopenharmony_ci } 2251cb0ef41Sopenharmony_ci} 2261cb0ef41Sopenharmony_ci 2271cb0ef41Sopenharmony_ciexports.Domain = Domain; 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ciexports.create = exports.createDomain = function createDomain() { 2301cb0ef41Sopenharmony_ci return new Domain(); 2311cb0ef41Sopenharmony_ci}; 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_ci// The active domain is always the one that we're currently in. 2341cb0ef41Sopenharmony_ciexports.active = null; 2351cb0ef41Sopenharmony_ciDomain.prototype.members = undefined; 2361cb0ef41Sopenharmony_ci 2371cb0ef41Sopenharmony_ci// Called by process._fatalException in case an error was thrown. 2381cb0ef41Sopenharmony_ciDomain.prototype._errorHandler = function(er) { 2391cb0ef41Sopenharmony_ci let caught = false; 2401cb0ef41Sopenharmony_ci 2411cb0ef41Sopenharmony_ci if ((typeof er === 'object' && er !== null) || typeof er === 'function') { 2421cb0ef41Sopenharmony_ci ObjectDefineProperty(er, 'domain', { 2431cb0ef41Sopenharmony_ci __proto__: null, 2441cb0ef41Sopenharmony_ci configurable: true, 2451cb0ef41Sopenharmony_ci enumerable: false, 2461cb0ef41Sopenharmony_ci value: this, 2471cb0ef41Sopenharmony_ci writable: true, 2481cb0ef41Sopenharmony_ci }); 2491cb0ef41Sopenharmony_ci er.domainThrown = true; 2501cb0ef41Sopenharmony_ci } 2511cb0ef41Sopenharmony_ci // Pop all adjacent duplicates of the currently active domain from the stack. 2521cb0ef41Sopenharmony_ci // This is done to prevent a domain's error handler to run within the context 2531cb0ef41Sopenharmony_ci // of itself, and re-entering itself recursively handler as a result of an 2541cb0ef41Sopenharmony_ci // exception thrown in its context. 2551cb0ef41Sopenharmony_ci while (exports.active === this) { 2561cb0ef41Sopenharmony_ci this.exit(); 2571cb0ef41Sopenharmony_ci } 2581cb0ef41Sopenharmony_ci 2591cb0ef41Sopenharmony_ci // The top-level domain-handler is handled separately. 2601cb0ef41Sopenharmony_ci // 2611cb0ef41Sopenharmony_ci // The reason is that if V8 was passed a command line option 2621cb0ef41Sopenharmony_ci // asking it to abort on an uncaught exception (currently 2631cb0ef41Sopenharmony_ci // "--abort-on-uncaught-exception"), we want an uncaught exception 2641cb0ef41Sopenharmony_ci // in the top-level domain error handler to make the 2651cb0ef41Sopenharmony_ci // process abort. Using try/catch here would always make V8 think 2661cb0ef41Sopenharmony_ci // that these exceptions are caught, and thus would prevent it from 2671cb0ef41Sopenharmony_ci // aborting in these cases. 2681cb0ef41Sopenharmony_ci if (stack.length === 0) { 2691cb0ef41Sopenharmony_ci // If there's no error handler, do not emit an 'error' event 2701cb0ef41Sopenharmony_ci // as this would throw an error, make the process exit, and thus 2711cb0ef41Sopenharmony_ci // prevent the process 'uncaughtException' event from being emitted 2721cb0ef41Sopenharmony_ci // if a listener is set. 2731cb0ef41Sopenharmony_ci if (EventEmitter.listenerCount(this, 'error') > 0) { 2741cb0ef41Sopenharmony_ci // Clear the uncaughtExceptionCaptureCallback so that we know that, since 2751cb0ef41Sopenharmony_ci // the top-level domain is not active anymore, it would be ok to abort on 2761cb0ef41Sopenharmony_ci // an uncaught exception at this point 2771cb0ef41Sopenharmony_ci setUncaughtExceptionCaptureCallback(null); 2781cb0ef41Sopenharmony_ci try { 2791cb0ef41Sopenharmony_ci caught = this.emit('error', er); 2801cb0ef41Sopenharmony_ci } finally { 2811cb0ef41Sopenharmony_ci updateExceptionCapture(); 2821cb0ef41Sopenharmony_ci } 2831cb0ef41Sopenharmony_ci } 2841cb0ef41Sopenharmony_ci } else { 2851cb0ef41Sopenharmony_ci // Wrap this in a try/catch so we don't get infinite throwing 2861cb0ef41Sopenharmony_ci try { 2871cb0ef41Sopenharmony_ci // One of three things will happen here. 2881cb0ef41Sopenharmony_ci // 2891cb0ef41Sopenharmony_ci // 1. There is a handler, caught = true 2901cb0ef41Sopenharmony_ci // 2. There is no handler, caught = false 2911cb0ef41Sopenharmony_ci // 3. It throws, caught = false 2921cb0ef41Sopenharmony_ci // 2931cb0ef41Sopenharmony_ci // If caught is false after this, then there's no need to exit() 2941cb0ef41Sopenharmony_ci // the domain, because we're going to crash the process anyway. 2951cb0ef41Sopenharmony_ci caught = this.emit('error', er); 2961cb0ef41Sopenharmony_ci } catch (er2) { 2971cb0ef41Sopenharmony_ci // The domain error handler threw! oh no! 2981cb0ef41Sopenharmony_ci // See if another domain can catch THIS error, 2991cb0ef41Sopenharmony_ci // or else crash on the original one. 3001cb0ef41Sopenharmony_ci updateExceptionCapture(); 3011cb0ef41Sopenharmony_ci if (stack.length) { 3021cb0ef41Sopenharmony_ci exports.active = process.domain = stack[stack.length - 1]; 3031cb0ef41Sopenharmony_ci caught = process.domain._errorHandler(er2); 3041cb0ef41Sopenharmony_ci } else { 3051cb0ef41Sopenharmony_ci // Pass on to the next exception handler. 3061cb0ef41Sopenharmony_ci throw er2; 3071cb0ef41Sopenharmony_ci } 3081cb0ef41Sopenharmony_ci } 3091cb0ef41Sopenharmony_ci } 3101cb0ef41Sopenharmony_ci 3111cb0ef41Sopenharmony_ci // Exit all domains on the stack. Uncaught exceptions end the 3121cb0ef41Sopenharmony_ci // current tick and no domains should be left on the stack 3131cb0ef41Sopenharmony_ci // between ticks. 3141cb0ef41Sopenharmony_ci domainUncaughtExceptionClear(); 3151cb0ef41Sopenharmony_ci 3161cb0ef41Sopenharmony_ci return caught; 3171cb0ef41Sopenharmony_ci}; 3181cb0ef41Sopenharmony_ci 3191cb0ef41Sopenharmony_ci 3201cb0ef41Sopenharmony_ciDomain.prototype.enter = function() { 3211cb0ef41Sopenharmony_ci // Note that this might be a no-op, but we still need 3221cb0ef41Sopenharmony_ci // to push it onto the stack so that we can pop it later. 3231cb0ef41Sopenharmony_ci exports.active = process.domain = this; 3241cb0ef41Sopenharmony_ci ArrayPrototypePush(stack, this); 3251cb0ef41Sopenharmony_ci updateExceptionCapture(); 3261cb0ef41Sopenharmony_ci}; 3271cb0ef41Sopenharmony_ci 3281cb0ef41Sopenharmony_ci 3291cb0ef41Sopenharmony_ciDomain.prototype.exit = function() { 3301cb0ef41Sopenharmony_ci // Don't do anything if this domain is not on the stack. 3311cb0ef41Sopenharmony_ci const index = ArrayPrototypeLastIndexOf(stack, this); 3321cb0ef41Sopenharmony_ci if (index === -1) return; 3331cb0ef41Sopenharmony_ci 3341cb0ef41Sopenharmony_ci // Exit all domains until this one. 3351cb0ef41Sopenharmony_ci ArrayPrototypeSplice(stack, index); 3361cb0ef41Sopenharmony_ci 3371cb0ef41Sopenharmony_ci exports.active = stack.length === 0 ? undefined : stack[stack.length - 1]; 3381cb0ef41Sopenharmony_ci process.domain = exports.active; 3391cb0ef41Sopenharmony_ci updateExceptionCapture(); 3401cb0ef41Sopenharmony_ci}; 3411cb0ef41Sopenharmony_ci 3421cb0ef41Sopenharmony_ci 3431cb0ef41Sopenharmony_ci// note: this works for timers as well. 3441cb0ef41Sopenharmony_ciDomain.prototype.add = function(ee) { 3451cb0ef41Sopenharmony_ci // If the domain is already added, then nothing left to do. 3461cb0ef41Sopenharmony_ci if (ee.domain === this) 3471cb0ef41Sopenharmony_ci return; 3481cb0ef41Sopenharmony_ci 3491cb0ef41Sopenharmony_ci // Has a domain already - remove it first. 3501cb0ef41Sopenharmony_ci if (ee.domain) 3511cb0ef41Sopenharmony_ci ee.domain.remove(ee); 3521cb0ef41Sopenharmony_ci 3531cb0ef41Sopenharmony_ci // Check for circular Domain->Domain links. 3541cb0ef41Sopenharmony_ci // They cause big issues. 3551cb0ef41Sopenharmony_ci // 3561cb0ef41Sopenharmony_ci // For example: 3571cb0ef41Sopenharmony_ci // var d = domain.create(); 3581cb0ef41Sopenharmony_ci // var e = domain.create(); 3591cb0ef41Sopenharmony_ci // d.add(e); 3601cb0ef41Sopenharmony_ci // e.add(d); 3611cb0ef41Sopenharmony_ci // e.emit('error', er); // RangeError, stack overflow! 3621cb0ef41Sopenharmony_ci if (this.domain && (ee instanceof Domain)) { 3631cb0ef41Sopenharmony_ci for (let d = this.domain; d; d = d.domain) { 3641cb0ef41Sopenharmony_ci if (ee === d) return; 3651cb0ef41Sopenharmony_ci } 3661cb0ef41Sopenharmony_ci } 3671cb0ef41Sopenharmony_ci 3681cb0ef41Sopenharmony_ci ObjectDefineProperty(ee, 'domain', { 3691cb0ef41Sopenharmony_ci __proto__: null, 3701cb0ef41Sopenharmony_ci configurable: true, 3711cb0ef41Sopenharmony_ci enumerable: false, 3721cb0ef41Sopenharmony_ci value: this, 3731cb0ef41Sopenharmony_ci writable: true, 3741cb0ef41Sopenharmony_ci }); 3751cb0ef41Sopenharmony_ci ArrayPrototypePush(this.members, ee); 3761cb0ef41Sopenharmony_ci}; 3771cb0ef41Sopenharmony_ci 3781cb0ef41Sopenharmony_ci 3791cb0ef41Sopenharmony_ciDomain.prototype.remove = function(ee) { 3801cb0ef41Sopenharmony_ci ee.domain = null; 3811cb0ef41Sopenharmony_ci const index = ArrayPrototypeIndexOf(this.members, ee); 3821cb0ef41Sopenharmony_ci if (index !== -1) 3831cb0ef41Sopenharmony_ci ArrayPrototypeSplice(this.members, index, 1); 3841cb0ef41Sopenharmony_ci}; 3851cb0ef41Sopenharmony_ci 3861cb0ef41Sopenharmony_ci 3871cb0ef41Sopenharmony_ciDomain.prototype.run = function(fn) { 3881cb0ef41Sopenharmony_ci this.enter(); 3891cb0ef41Sopenharmony_ci const ret = ReflectApply(fn, this, ArrayPrototypeSlice(arguments, 1)); 3901cb0ef41Sopenharmony_ci this.exit(); 3911cb0ef41Sopenharmony_ci 3921cb0ef41Sopenharmony_ci return ret; 3931cb0ef41Sopenharmony_ci}; 3941cb0ef41Sopenharmony_ci 3951cb0ef41Sopenharmony_ci 3961cb0ef41Sopenharmony_cifunction intercepted(_this, self, cb, fnargs) { 3971cb0ef41Sopenharmony_ci if (fnargs[0] && fnargs[0] instanceof Error) { 3981cb0ef41Sopenharmony_ci const er = fnargs[0]; 3991cb0ef41Sopenharmony_ci er.domainBound = cb; 4001cb0ef41Sopenharmony_ci er.domainThrown = false; 4011cb0ef41Sopenharmony_ci ObjectDefineProperty(er, 'domain', { 4021cb0ef41Sopenharmony_ci __proto__: null, 4031cb0ef41Sopenharmony_ci configurable: true, 4041cb0ef41Sopenharmony_ci enumerable: false, 4051cb0ef41Sopenharmony_ci value: self, 4061cb0ef41Sopenharmony_ci writable: true, 4071cb0ef41Sopenharmony_ci }); 4081cb0ef41Sopenharmony_ci self.emit('error', er); 4091cb0ef41Sopenharmony_ci return; 4101cb0ef41Sopenharmony_ci } 4111cb0ef41Sopenharmony_ci 4121cb0ef41Sopenharmony_ci self.enter(); 4131cb0ef41Sopenharmony_ci const ret = ReflectApply(cb, _this, ArrayPrototypeSlice(fnargs, 1)); 4141cb0ef41Sopenharmony_ci self.exit(); 4151cb0ef41Sopenharmony_ci 4161cb0ef41Sopenharmony_ci return ret; 4171cb0ef41Sopenharmony_ci} 4181cb0ef41Sopenharmony_ci 4191cb0ef41Sopenharmony_ci 4201cb0ef41Sopenharmony_ciDomain.prototype.intercept = function(cb) { 4211cb0ef41Sopenharmony_ci const self = this; 4221cb0ef41Sopenharmony_ci 4231cb0ef41Sopenharmony_ci function runIntercepted() { 4241cb0ef41Sopenharmony_ci return intercepted(this, self, cb, arguments); 4251cb0ef41Sopenharmony_ci } 4261cb0ef41Sopenharmony_ci 4271cb0ef41Sopenharmony_ci return runIntercepted; 4281cb0ef41Sopenharmony_ci}; 4291cb0ef41Sopenharmony_ci 4301cb0ef41Sopenharmony_ci 4311cb0ef41Sopenharmony_cifunction bound(_this, self, cb, fnargs) { 4321cb0ef41Sopenharmony_ci self.enter(); 4331cb0ef41Sopenharmony_ci const ret = ReflectApply(cb, _this, fnargs); 4341cb0ef41Sopenharmony_ci self.exit(); 4351cb0ef41Sopenharmony_ci 4361cb0ef41Sopenharmony_ci return ret; 4371cb0ef41Sopenharmony_ci} 4381cb0ef41Sopenharmony_ci 4391cb0ef41Sopenharmony_ci 4401cb0ef41Sopenharmony_ciDomain.prototype.bind = function(cb) { 4411cb0ef41Sopenharmony_ci const self = this; 4421cb0ef41Sopenharmony_ci 4431cb0ef41Sopenharmony_ci function runBound() { 4441cb0ef41Sopenharmony_ci return bound(this, self, cb, arguments); 4451cb0ef41Sopenharmony_ci } 4461cb0ef41Sopenharmony_ci 4471cb0ef41Sopenharmony_ci ObjectDefineProperty(runBound, 'domain', { 4481cb0ef41Sopenharmony_ci __proto__: null, 4491cb0ef41Sopenharmony_ci configurable: true, 4501cb0ef41Sopenharmony_ci enumerable: false, 4511cb0ef41Sopenharmony_ci value: this, 4521cb0ef41Sopenharmony_ci writable: true, 4531cb0ef41Sopenharmony_ci }); 4541cb0ef41Sopenharmony_ci 4551cb0ef41Sopenharmony_ci return runBound; 4561cb0ef41Sopenharmony_ci}; 4571cb0ef41Sopenharmony_ci 4581cb0ef41Sopenharmony_ci// Override EventEmitter methods to make it domain-aware. 4591cb0ef41Sopenharmony_ciEventEmitter.usingDomains = true; 4601cb0ef41Sopenharmony_ci 4611cb0ef41Sopenharmony_ciconst eventInit = EventEmitter.init; 4621cb0ef41Sopenharmony_ciEventEmitter.init = function(opts) { 4631cb0ef41Sopenharmony_ci ObjectDefineProperty(this, 'domain', { 4641cb0ef41Sopenharmony_ci __proto__: null, 4651cb0ef41Sopenharmony_ci configurable: true, 4661cb0ef41Sopenharmony_ci enumerable: false, 4671cb0ef41Sopenharmony_ci value: null, 4681cb0ef41Sopenharmony_ci writable: true, 4691cb0ef41Sopenharmony_ci }); 4701cb0ef41Sopenharmony_ci if (exports.active && !(this instanceof exports.Domain)) { 4711cb0ef41Sopenharmony_ci this.domain = exports.active; 4721cb0ef41Sopenharmony_ci } 4731cb0ef41Sopenharmony_ci 4741cb0ef41Sopenharmony_ci return FunctionPrototypeCall(eventInit, this, opts); 4751cb0ef41Sopenharmony_ci}; 4761cb0ef41Sopenharmony_ci 4771cb0ef41Sopenharmony_ciconst eventEmit = EventEmitter.prototype.emit; 4781cb0ef41Sopenharmony_ciEventEmitter.prototype.emit = function emit(...args) { 4791cb0ef41Sopenharmony_ci const domain = this.domain; 4801cb0ef41Sopenharmony_ci 4811cb0ef41Sopenharmony_ci const type = args[0]; 4821cb0ef41Sopenharmony_ci const shouldEmitError = type === 'error' && 4831cb0ef41Sopenharmony_ci this.listenerCount(type) > 0; 4841cb0ef41Sopenharmony_ci 4851cb0ef41Sopenharmony_ci // Just call original `emit` if current EE instance has `error` 4861cb0ef41Sopenharmony_ci // handler, there's no active domain or this is process 4871cb0ef41Sopenharmony_ci if (shouldEmitError || domain === null || domain === undefined || 4881cb0ef41Sopenharmony_ci this === process) { 4891cb0ef41Sopenharmony_ci return ReflectApply(eventEmit, this, args); 4901cb0ef41Sopenharmony_ci } 4911cb0ef41Sopenharmony_ci 4921cb0ef41Sopenharmony_ci if (type === 'error') { 4931cb0ef41Sopenharmony_ci const er = args.length > 1 && args[1] ? 4941cb0ef41Sopenharmony_ci args[1] : new ERR_UNHANDLED_ERROR(); 4951cb0ef41Sopenharmony_ci 4961cb0ef41Sopenharmony_ci if (typeof er === 'object') { 4971cb0ef41Sopenharmony_ci er.domainEmitter = this; 4981cb0ef41Sopenharmony_ci ObjectDefineProperty(er, 'domain', { 4991cb0ef41Sopenharmony_ci __proto__: null, 5001cb0ef41Sopenharmony_ci configurable: true, 5011cb0ef41Sopenharmony_ci enumerable: false, 5021cb0ef41Sopenharmony_ci value: domain, 5031cb0ef41Sopenharmony_ci writable: true, 5041cb0ef41Sopenharmony_ci }); 5051cb0ef41Sopenharmony_ci er.domainThrown = false; 5061cb0ef41Sopenharmony_ci } 5071cb0ef41Sopenharmony_ci 5081cb0ef41Sopenharmony_ci // Remove the current domain (and its duplicates) from the domains stack and 5091cb0ef41Sopenharmony_ci // set the active domain to its parent (if any) so that the domain's error 5101cb0ef41Sopenharmony_ci // handler doesn't run in its own context. This prevents any event emitter 5111cb0ef41Sopenharmony_ci // created or any exception thrown in that error handler from recursively 5121cb0ef41Sopenharmony_ci // executing that error handler. 5131cb0ef41Sopenharmony_ci const origDomainsStack = ArrayPrototypeSlice(stack); 5141cb0ef41Sopenharmony_ci const origActiveDomain = process.domain; 5151cb0ef41Sopenharmony_ci 5161cb0ef41Sopenharmony_ci // Travel the domains stack from top to bottom to find the first domain 5171cb0ef41Sopenharmony_ci // instance that is not a duplicate of the current active domain. 5181cb0ef41Sopenharmony_ci let idx = stack.length - 1; 5191cb0ef41Sopenharmony_ci while (idx > -1 && process.domain === stack[idx]) { 5201cb0ef41Sopenharmony_ci --idx; 5211cb0ef41Sopenharmony_ci } 5221cb0ef41Sopenharmony_ci 5231cb0ef41Sopenharmony_ci // Change the stack to not contain the current active domain, and only the 5241cb0ef41Sopenharmony_ci // domains above it on the stack. 5251cb0ef41Sopenharmony_ci if (idx < 0) { 5261cb0ef41Sopenharmony_ci stack.length = 0; 5271cb0ef41Sopenharmony_ci } else { 5281cb0ef41Sopenharmony_ci ArrayPrototypeSplice(stack, idx + 1); 5291cb0ef41Sopenharmony_ci } 5301cb0ef41Sopenharmony_ci 5311cb0ef41Sopenharmony_ci // Change the current active domain 5321cb0ef41Sopenharmony_ci if (stack.length > 0) { 5331cb0ef41Sopenharmony_ci exports.active = process.domain = stack[stack.length - 1]; 5341cb0ef41Sopenharmony_ci } else { 5351cb0ef41Sopenharmony_ci exports.active = process.domain = null; 5361cb0ef41Sopenharmony_ci } 5371cb0ef41Sopenharmony_ci 5381cb0ef41Sopenharmony_ci updateExceptionCapture(); 5391cb0ef41Sopenharmony_ci 5401cb0ef41Sopenharmony_ci domain.emit('error', er); 5411cb0ef41Sopenharmony_ci 5421cb0ef41Sopenharmony_ci // Now that the domain's error handler has completed, restore the domains 5431cb0ef41Sopenharmony_ci // stack and the active domain to their original values. 5441cb0ef41Sopenharmony_ci exports._stack = stack = origDomainsStack; 5451cb0ef41Sopenharmony_ci exports.active = process.domain = origActiveDomain; 5461cb0ef41Sopenharmony_ci updateExceptionCapture(); 5471cb0ef41Sopenharmony_ci 5481cb0ef41Sopenharmony_ci return false; 5491cb0ef41Sopenharmony_ci } 5501cb0ef41Sopenharmony_ci 5511cb0ef41Sopenharmony_ci domain.enter(); 5521cb0ef41Sopenharmony_ci const ret = ReflectApply(eventEmit, this, args); 5531cb0ef41Sopenharmony_ci domain.exit(); 5541cb0ef41Sopenharmony_ci 5551cb0ef41Sopenharmony_ci return ret; 5561cb0ef41Sopenharmony_ci}; 557