1'use strict'; 2 3const { 4 ArrayBufferPrototypeGetByteLength, 5 ArrayFrom, 6 ArrayIsArray, 7 ArrayPrototypePush, 8 ArrayPrototypeSlice, 9 ArrayPrototypeSort, 10 Error, 11 FunctionPrototypeCall, 12 ObjectCreate, 13 ObjectDefineProperties, 14 ObjectDefineProperty, 15 ObjectGetOwnPropertyDescriptor, 16 ObjectGetOwnPropertyDescriptors, 17 ObjectGetPrototypeOf, 18 ObjectFreeze, 19 ObjectPrototypeHasOwnProperty, 20 ObjectSetPrototypeOf, 21 ObjectValues, 22 Promise, 23 ReflectApply, 24 ReflectConstruct, 25 RegExpPrototypeExec, 26 RegExpPrototypeGetDotAll, 27 RegExpPrototypeGetGlobal, 28 RegExpPrototypeGetHasIndices, 29 RegExpPrototypeGetIgnoreCase, 30 RegExpPrototypeGetMultiline, 31 RegExpPrototypeGetSticky, 32 RegExpPrototypeGetUnicode, 33 RegExpPrototypeGetSource, 34 SafeMap, 35 SafeSet, 36 SafeWeakMap, 37 StringPrototypeReplace, 38 StringPrototypeToLowerCase, 39 StringPrototypeToUpperCase, 40 Symbol, 41 SymbolFor, 42 SymbolReplace, 43 SymbolSplit, 44} = primordials; 45 46const { 47 hideStackFrames, 48 codes: { 49 ERR_NO_CRYPTO, 50 ERR_UNKNOWN_SIGNAL, 51 }, 52 uvErrmapGet, 53 overrideStackTrace, 54} = require('internal/errors'); 55const { signals } = internalBinding('constants').os; 56const { 57 isArrayBufferDetached: _isArrayBufferDetached, 58 privateSymbols: { 59 arrow_message_private_symbol, 60 decorated_private_symbol, 61 }, 62 sleep: _sleep, 63 toUSVString: _toUSVString, 64} = internalBinding('util'); 65const { isNativeError } = internalBinding('types'); 66 67const noCrypto = !process.versions.openssl; 68 69const experimentalWarnings = new SafeSet(); 70 71const colorRegExp = /\u001b\[\d\d?m/g; // eslint-disable-line no-control-regex 72 73const unpairedSurrogateRe = 74 /(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])/; 75function toUSVString(val) { 76 const str = `${val}`; 77 // As of V8 5.5, `str.search()` (and `unpairedSurrogateRe[@@search]()`) are 78 // slower than `unpairedSurrogateRe.exec()`. 79 const match = RegExpPrototypeExec(unpairedSurrogateRe, str); 80 if (!match) 81 return str; 82 return _toUSVString(str, match.index); 83} 84 85let uvBinding; 86 87function lazyUv() { 88 uvBinding ??= internalBinding('uv'); 89 return uvBinding; 90} 91 92function removeColors(str) { 93 return StringPrototypeReplace(str, colorRegExp, ''); 94} 95 96function isError(e) { 97 // An error could be an instance of Error while not being a native error 98 // or could be from a different realm and not be instance of Error but still 99 // be a native error. 100 return isNativeError(e) || e instanceof Error; 101} 102 103// Keep a list of deprecation codes that have been warned on so we only warn on 104// each one once. 105const codesWarned = new SafeSet(); 106 107let validateString; 108 109// Mark that a method should not be used. 110// Returns a modified function which warns once by default. 111// If --no-deprecation is set, then it is a no-op. 112function deprecate(fn, msg, code) { 113 if (process.noDeprecation === true) { 114 return fn; 115 } 116 117 // Lazy-load to avoid a circular dependency. 118 if (validateString === undefined) 119 ({ validateString } = require('internal/validators')); 120 121 if (code !== undefined) 122 validateString(code, 'code'); 123 124 let warned = false; 125 function deprecated(...args) { 126 if (!warned) { 127 warned = true; 128 if (code !== undefined) { 129 if (!codesWarned.has(code)) { 130 process.emitWarning(msg, 'DeprecationWarning', code, deprecated); 131 codesWarned.add(code); 132 } 133 } else { 134 process.emitWarning(msg, 'DeprecationWarning', deprecated); 135 } 136 } 137 if (new.target) { 138 return ReflectConstruct(fn, args, new.target); 139 } 140 return ReflectApply(fn, this, args); 141 } 142 143 // The wrapper will keep the same prototype as fn to maintain prototype chain 144 ObjectSetPrototypeOf(deprecated, fn); 145 if (fn.prototype) { 146 // Setting this (rather than using Object.setPrototype, as above) ensures 147 // that calling the unwrapped constructor gives an instanceof the wrapped 148 // constructor. 149 deprecated.prototype = fn.prototype; 150 } 151 152 return deprecated; 153} 154 155function decorateErrorStack(err) { 156 if (!(isError(err) && err.stack) || err[decorated_private_symbol]) 157 return; 158 159 const arrow = err[arrow_message_private_symbol]; 160 161 if (arrow) { 162 err.stack = arrow + err.stack; 163 err[decorated_private_symbol] = true; 164 } 165} 166 167function assertCrypto() { 168 if (noCrypto) 169 throw new ERR_NO_CRYPTO(); 170} 171 172// Return undefined if there is no match. 173// Move the "slow cases" to a separate function to make sure this function gets 174// inlined properly. That prioritizes the common case. 175function normalizeEncoding(enc) { 176 if (enc == null || enc === 'utf8' || enc === 'utf-8') return 'utf8'; 177 return slowCases(enc); 178} 179 180function slowCases(enc) { 181 switch (enc.length) { 182 case 4: 183 if (enc === 'UTF8') return 'utf8'; 184 if (enc === 'ucs2' || enc === 'UCS2') return 'utf16le'; 185 enc = `${enc}`.toLowerCase(); 186 if (enc === 'utf8') return 'utf8'; 187 if (enc === 'ucs2') return 'utf16le'; 188 break; 189 case 3: 190 if (enc === 'hex' || enc === 'HEX' || 191 `${enc}`.toLowerCase() === 'hex') 192 return 'hex'; 193 break; 194 case 5: 195 if (enc === 'ascii') return 'ascii'; 196 if (enc === 'ucs-2') return 'utf16le'; 197 if (enc === 'UTF-8') return 'utf8'; 198 if (enc === 'ASCII') return 'ascii'; 199 if (enc === 'UCS-2') return 'utf16le'; 200 enc = `${enc}`.toLowerCase(); 201 if (enc === 'utf-8') return 'utf8'; 202 if (enc === 'ascii') return 'ascii'; 203 if (enc === 'ucs-2') return 'utf16le'; 204 break; 205 case 6: 206 if (enc === 'base64') return 'base64'; 207 if (enc === 'latin1' || enc === 'binary') return 'latin1'; 208 if (enc === 'BASE64') return 'base64'; 209 if (enc === 'LATIN1' || enc === 'BINARY') return 'latin1'; 210 enc = `${enc}`.toLowerCase(); 211 if (enc === 'base64') return 'base64'; 212 if (enc === 'latin1' || enc === 'binary') return 'latin1'; 213 break; 214 case 7: 215 if (enc === 'utf16le' || enc === 'UTF16LE' || 216 `${enc}`.toLowerCase() === 'utf16le') 217 return 'utf16le'; 218 break; 219 case 8: 220 if (enc === 'utf-16le' || enc === 'UTF-16LE' || 221 `${enc}`.toLowerCase() === 'utf-16le') 222 return 'utf16le'; 223 break; 224 case 9: 225 if (enc === 'base64url' || enc === 'BASE64URL' || 226 `${enc}`.toLowerCase() === 'base64url') 227 return 'base64url'; 228 break; 229 default: 230 if (enc === '') return 'utf8'; 231 } 232} 233 234function emitExperimentalWarning(feature) { 235 if (experimentalWarnings.has(feature)) return; 236 const msg = `${feature} is an experimental feature and might change at any time`; 237 experimentalWarnings.add(feature); 238 process.emitWarning(msg, 'ExperimentalWarning'); 239} 240 241function filterDuplicateStrings(items, low) { 242 const map = new SafeMap(); 243 for (let i = 0; i < items.length; i++) { 244 const item = items[i]; 245 const key = StringPrototypeToLowerCase(item); 246 if (low) { 247 map.set(key, key); 248 } else { 249 map.set(key, item); 250 } 251 } 252 return ArrayPrototypeSort(ArrayFrom(map.values())); 253} 254 255function cachedResult(fn) { 256 let result; 257 return () => { 258 if (result === undefined) 259 result = fn(); 260 return ArrayPrototypeSlice(result); 261 }; 262} 263 264// Useful for Wrapping an ES6 Class with a constructor Function that 265// does not require the new keyword. For instance: 266// class A { constructor(x) {this.x = x;}} 267// const B = createClassWrapper(A); 268// B() instanceof A // true 269// B() instanceof B // true 270function createClassWrapper(type) { 271 function fn(...args) { 272 return ReflectConstruct(type, args, new.target || type); 273 } 274 // Mask the wrapper function name and length values 275 ObjectDefineProperties(fn, { 276 name: { __proto__: null, value: type.name }, 277 length: { __proto__: null, value: type.length }, 278 }); 279 ObjectSetPrototypeOf(fn, type); 280 fn.prototype = type.prototype; 281 return fn; 282} 283 284let signalsToNamesMapping; 285function getSignalsToNamesMapping() { 286 if (signalsToNamesMapping !== undefined) 287 return signalsToNamesMapping; 288 289 signalsToNamesMapping = ObjectCreate(null); 290 for (const key in signals) { 291 signalsToNamesMapping[signals[key]] = key; 292 } 293 294 return signalsToNamesMapping; 295} 296 297function convertToValidSignal(signal) { 298 if (typeof signal === 'number' && getSignalsToNamesMapping()[signal]) 299 return signal; 300 301 if (typeof signal === 'string') { 302 const signalName = signals[StringPrototypeToUpperCase(signal)]; 303 if (signalName) return signalName; 304 } 305 306 throw new ERR_UNKNOWN_SIGNAL(signal); 307} 308 309function getConstructorOf(obj) { 310 while (obj) { 311 const descriptor = ObjectGetOwnPropertyDescriptor(obj, 'constructor'); 312 if (descriptor !== undefined && 313 typeof descriptor.value === 'function' && 314 descriptor.value.name !== '') { 315 return descriptor.value; 316 } 317 318 obj = ObjectGetPrototypeOf(obj); 319 } 320 321 return null; 322} 323 324function getSystemErrorName(err) { 325 const entry = uvErrmapGet(err); 326 return entry ? entry[0] : `Unknown system error ${err}`; 327} 328 329function getSystemErrorMap() { 330 return lazyUv().getErrorMap(); 331} 332 333const kCustomPromisifiedSymbol = SymbolFor('nodejs.util.promisify.custom'); 334const kCustomPromisifyArgsSymbol = Symbol('customPromisifyArgs'); 335 336let validateFunction; 337 338function promisify(original) { 339 // Lazy-load to avoid a circular dependency. 340 if (validateFunction === undefined) 341 ({ validateFunction } = require('internal/validators')); 342 343 validateFunction(original, 'original'); 344 345 if (original[kCustomPromisifiedSymbol]) { 346 const fn = original[kCustomPromisifiedSymbol]; 347 348 validateFunction(fn, 'util.promisify.custom'); 349 350 return ObjectDefineProperty(fn, kCustomPromisifiedSymbol, { 351 __proto__: null, 352 value: fn, enumerable: false, writable: false, configurable: true, 353 }); 354 } 355 356 // Names to create an object from in case the callback receives multiple 357 // arguments, e.g. ['bytesRead', 'buffer'] for fs.read. 358 const argumentNames = original[kCustomPromisifyArgsSymbol]; 359 360 function fn(...args) { 361 return new Promise((resolve, reject) => { 362 ArrayPrototypePush(args, (err, ...values) => { 363 if (err) { 364 return reject(err); 365 } 366 if (argumentNames !== undefined && values.length > 1) { 367 const obj = {}; 368 for (let i = 0; i < argumentNames.length; i++) 369 obj[argumentNames[i]] = values[i]; 370 resolve(obj); 371 } else { 372 resolve(values[0]); 373 } 374 }); 375 ReflectApply(original, this, args); 376 }); 377 } 378 379 ObjectSetPrototypeOf(fn, ObjectGetPrototypeOf(original)); 380 381 ObjectDefineProperty(fn, kCustomPromisifiedSymbol, { 382 __proto__: null, 383 value: fn, enumerable: false, writable: false, configurable: true, 384 }); 385 386 const descriptors = ObjectGetOwnPropertyDescriptors(original); 387 const propertiesValues = ObjectValues(descriptors); 388 for (let i = 0; i < propertiesValues.length; i++) { 389 // We want to use null-prototype objects to not rely on globally mutable 390 // %Object.prototype%. 391 ObjectSetPrototypeOf(propertiesValues[i], null); 392 } 393 return ObjectDefineProperties(fn, descriptors); 394} 395 396promisify.custom = kCustomPromisifiedSymbol; 397 398// The built-in Array#join is slower in v8 6.0 399function join(output, separator) { 400 let str = ''; 401 if (output.length !== 0) { 402 const lastIndex = output.length - 1; 403 for (let i = 0; i < lastIndex; i++) { 404 // It is faster not to use a template string here 405 str += output[i]; 406 str += separator; 407 } 408 str += output[lastIndex]; 409 } 410 return str; 411} 412 413// As of V8 6.6, depending on the size of the array, this is anywhere 414// between 1.5-10x faster than the two-arg version of Array#splice() 415function spliceOne(list, index) { 416 for (; index + 1 < list.length; index++) 417 list[index] = list[index + 1]; 418 list.pop(); 419} 420 421const kNodeModulesRE = /^(.*)[\\/]node_modules[\\/]/; 422 423let getStructuredStack; 424 425function isInsideNodeModules() { 426 if (getStructuredStack === undefined) { 427 // Lazy-load to avoid a circular dependency. 428 const { runInNewContext } = require('vm'); 429 // Use `runInNewContext()` to get something tamper-proof and 430 // side-effect-free. Since this is currently only used for a deprecated API, 431 // the perf implications should be okay. 432 getStructuredStack = runInNewContext(`(function() { 433 try { Error.stackTraceLimit = Infinity; } catch {} 434 return function structuredStack() { 435 const e = new Error(); 436 overrideStackTrace.set(e, (err, trace) => trace); 437 return e.stack; 438 }; 439 })()`, { overrideStackTrace }, { filename: 'structured-stack' }); 440 } 441 442 const stack = getStructuredStack(); 443 444 // Iterate over all stack frames and look for the first one not coming 445 // from inside Node.js itself: 446 if (ArrayIsArray(stack)) { 447 for (const frame of stack) { 448 const filename = frame.getFileName(); 449 // If a filename does not start with / or contain \, 450 // it's likely from Node.js core. 451 if (RegExpPrototypeExec(/^\/|\\/, filename) === null) 452 continue; 453 return RegExpPrototypeExec(kNodeModulesRE, filename) !== null; 454 } 455 } 456 return false; 457} 458 459function once(callback) { 460 let called = false; 461 return function(...args) { 462 if (called) return; 463 called = true; 464 return ReflectApply(callback, this, args); 465 }; 466} 467 468let validateUint32; 469 470function sleep(msec) { 471 // Lazy-load to avoid a circular dependency. 472 if (validateUint32 === undefined) 473 ({ validateUint32 } = require('internal/validators')); 474 475 validateUint32(msec, 'msec'); 476 _sleep(msec); 477} 478 479function createDeferredPromise() { 480 let resolve; 481 let reject; 482 const promise = new Promise((res, rej) => { 483 resolve = res; 484 reject = rej; 485 }); 486 487 return { promise, resolve, reject }; 488} 489 490// https://heycam.github.io/webidl/#define-the-operations 491function defineOperation(target, name, method) { 492 ObjectDefineProperty(target, name, { 493 __proto__: null, 494 writable: true, 495 enumerable: true, 496 configurable: true, 497 value: method, 498 }); 499} 500 501// https://heycam.github.io/webidl/#es-interfaces 502function exposeInterface(target, name, interfaceObject) { 503 ObjectDefineProperty(target, name, { 504 __proto__: null, 505 writable: true, 506 enumerable: false, 507 configurable: true, 508 value: interfaceObject, 509 }); 510} 511 512let _DOMException; 513const lazyDOMExceptionClass = () => { 514 _DOMException ??= internalBinding('messaging').DOMException; 515 return _DOMException; 516}; 517 518const lazyDOMException = hideStackFrames((message, name) => { 519 _DOMException ??= internalBinding('messaging').DOMException; 520 return new _DOMException(message, name); 521}); 522 523const kEnumerableProperty = ObjectCreate(null); 524kEnumerableProperty.enumerable = true; 525ObjectFreeze(kEnumerableProperty); 526 527const kEmptyObject = ObjectFreeze(ObjectCreate(null)); 528 529function filterOwnProperties(source, keys) { 530 const filtered = ObjectCreate(null); 531 for (let i = 0; i < keys.length; i++) { 532 const key = keys[i]; 533 if (ObjectPrototypeHasOwnProperty(source, key)) { 534 filtered[key] = source[key]; 535 } 536 } 537 538 return filtered; 539} 540 541/** 542 * Mimics `obj[key] = value` but ignoring potential prototype inheritance. 543 * @param {any} obj 544 * @param {string} key 545 * @param {any} value 546 * @returns {any} 547 */ 548function setOwnProperty(obj, key, value) { 549 return ObjectDefineProperty(obj, key, { 550 __proto__: null, 551 configurable: true, 552 enumerable: true, 553 value, 554 writable: true, 555 }); 556} 557 558let internalGlobal; 559function getInternalGlobal() { 560 if (internalGlobal == null) { 561 // Lazy-load to avoid a circular dependency. 562 const { runInNewContext } = require('vm'); 563 internalGlobal = runInNewContext('this', undefined, { contextName: 'internal' }); 564 } 565 return internalGlobal; 566} 567 568function SideEffectFreeRegExpPrototypeExec(regex, string) { 569 const { RegExp: RegExpFromAnotherRealm } = getInternalGlobal(); 570 return FunctionPrototypeCall(RegExpFromAnotherRealm.prototype.exec, regex, string); 571} 572 573const crossRelmRegexes = new SafeWeakMap(); 574function getCrossRelmRegex(regex) { 575 const cached = crossRelmRegexes.get(regex); 576 if (cached) return cached; 577 578 let flagString = ''; 579 if (RegExpPrototypeGetHasIndices(regex)) flagString += 'd'; 580 if (RegExpPrototypeGetGlobal(regex)) flagString += 'g'; 581 if (RegExpPrototypeGetIgnoreCase(regex)) flagString += 'i'; 582 if (RegExpPrototypeGetMultiline(regex)) flagString += 'm'; 583 if (RegExpPrototypeGetDotAll(regex)) flagString += 's'; 584 if (RegExpPrototypeGetUnicode(regex)) flagString += 'u'; 585 if (RegExpPrototypeGetSticky(regex)) flagString += 'y'; 586 587 const { RegExp: RegExpFromAnotherRealm } = getInternalGlobal(); 588 const crossRelmRegex = new RegExpFromAnotherRealm(RegExpPrototypeGetSource(regex), flagString); 589 crossRelmRegexes.set(regex, crossRelmRegex); 590 return crossRelmRegex; 591} 592 593function SideEffectFreeRegExpPrototypeSymbolReplace(regex, string, replacement) { 594 return getCrossRelmRegex(regex)[SymbolReplace](string, replacement); 595} 596 597function SideEffectFreeRegExpPrototypeSymbolSplit(regex, string, limit = undefined) { 598 return getCrossRelmRegex(regex)[SymbolSplit](string, limit); 599} 600 601 602function isArrayBufferDetached(value) { 603 if (ArrayBufferPrototypeGetByteLength(value) === 0) { 604 return _isArrayBufferDetached(value); 605 } 606 607 return false; 608} 609 610// Setup user-facing NODE_V8_COVERAGE environment variable that writes 611// ScriptCoverage objects to a specified directory. 612function setupCoverageHooks(dir) { 613 const cwd = require('internal/process/execution').tryGetCwd(); 614 const { resolve } = require('path'); 615 const coverageDirectory = resolve(cwd, dir); 616 const { sourceMapCacheToObject } = 617 require('internal/source_map/source_map_cache'); 618 619 if (process.features.inspector) { 620 internalBinding('profiler').setCoverageDirectory(coverageDirectory); 621 internalBinding('profiler').setSourceMapCacheGetter(sourceMapCacheToObject); 622 } else { 623 process.emitWarning('The inspector is disabled, ' + 624 'coverage could not be collected', 625 'Warning'); 626 return ''; 627 } 628 return coverageDirectory; 629} 630 631module.exports = { 632 assertCrypto, 633 cachedResult, 634 convertToValidSignal, 635 createClassWrapper, 636 createDeferredPromise, 637 decorateErrorStack, 638 defineOperation, 639 deprecate, 640 emitExperimentalWarning, 641 exposeInterface, 642 filterDuplicateStrings, 643 filterOwnProperties, 644 getConstructorOf, 645 getInternalGlobal, 646 getSystemErrorMap, 647 getSystemErrorName, 648 isArrayBufferDetached, 649 isError, 650 isInsideNodeModules, 651 join, 652 lazyDOMException, 653 lazyDOMExceptionClass, 654 normalizeEncoding, 655 once, 656 promisify, 657 SideEffectFreeRegExpPrototypeExec, 658 SideEffectFreeRegExpPrototypeSymbolReplace, 659 SideEffectFreeRegExpPrototypeSymbolSplit, 660 sleep, 661 spliceOne, 662 setupCoverageHooks, 663 toUSVString, 664 removeColors, 665 666 // Symbol used to customize promisify conversion 667 customPromisifyArgs: kCustomPromisifyArgsSymbol, 668 669 // Symbol used to provide a custom inspect function for an object as an 670 // alternative to using 'inspect' 671 customInspectSymbol: SymbolFor('nodejs.util.inspect.custom'), 672 673 // Used by the buffer module to capture an internal reference to the 674 // default isEncoding implementation, just in case userland overrides it. 675 kIsEncodingSymbol: Symbol('kIsEncodingSymbol'), 676 kVmBreakFirstLineSymbol: Symbol('kVmBreakFirstLineSymbol'), 677 678 kEmptyObject, 679 kEnumerableProperty, 680 setOwnProperty, 681}; 682