From 81fd4581b922079cf059d336d44272c288ea8fdf Mon Sep 17 00:00:00 2001 From: Brian White Date: Wed, 9 Mar 2016 22:40:54 -0500 Subject: [PATCH 01/48] tools: improve js linter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit switches from the eslint command-line tool to a custom tool that uses eslint programmatically in order to perform linting in parallel and to display linting results incrementally instead of buffering them until the end. Fixes: https://github.com/nodejs/node/issues/5596 PR-URL: https://github.com/nodejs/node/pull/5638 Reviewed-By: Ben Noordhuis Reviewed-By: Johan Bergström --- Makefile | 13 ++- tools/jslint.js | 262 ++++++++++++++++++++++++++++++++++++++++++++++++ vcbuild.bat | 9 +- 3 files changed, 279 insertions(+), 5 deletions(-) create mode 100644 tools/jslint.js diff --git a/Makefile b/Makefile index 401464c87a6..36681212673 100644 --- a/Makefile +++ b/Makefile @@ -603,8 +603,12 @@ bench-idle: $(NODE) benchmark/idle_clients.js & jslint: - $(NODE) tools/eslint/bin/eslint.js benchmark lib src test tools/doc \ - tools/eslint-rules --rulesdir tools/eslint-rules + $(NODE) tools/jslint.js -J benchmark lib src test tools/doc \ + tools/eslint-rules tools/jslint.js + +jslint-ci: + $(NODE) tools/jslint.js -f tap -o test-eslint.tap benchmark lib src test \ + tools/doc tools/eslint-rules tools/jslint.js CPPLINT_EXCLUDE ?= CPPLINT_EXCLUDE += src/node_lttng.cc @@ -633,14 +637,15 @@ cpplint: ifneq ("","$(wildcard tools/eslint/bin/eslint.js)") lint: jslint cpplint +lint-ci: jslint-ci cpplint else lint: @echo "Linting is not available through the source tarball." @echo "Use the git repo instead:" \ "$ git clone https://github.com/nodejs/node.git" -endif lint-ci: lint +endif .PHONY: lint cpplint jslint bench clean docopen docclean doc dist distclean \ check uninstall install install-includes install-bin all staticlib \ @@ -648,4 +653,4 @@ lint-ci: lint blog blogclean tar binary release-only bench-http-simple bench-idle \ bench-all bench bench-misc bench-array bench-buffer bench-net \ bench-http bench-fs bench-tls cctest run-ci test-v8 test-v8-intl \ - test-v8-benchmarks test-v8-all v8 lint-ci bench-ci + test-v8-benchmarks test-v8-all v8 lint-ci bench-ci jslint-ci diff --git a/tools/jslint.js b/tools/jslint.js new file mode 100644 index 00000000000..7cd2fd7bcb6 --- /dev/null +++ b/tools/jslint.js @@ -0,0 +1,262 @@ +'use strict'; + +const rulesDirs = ['tools/eslint-rules']; +// This is the maximum number of files to be linted per worker at any given time +const maxWorkload = 40; + +const cluster = require('cluster'); +const path = require('path'); +const fs = require('fs'); +const totalCPUs = require('os').cpus().length; + +const CLIEngine = require('./eslint').CLIEngine; +const glob = require('./eslint/node_modules/glob'); + +const cwd = process.cwd(); +const cli = new CLIEngine({ + rulePaths: rulesDirs +}); + +if (cluster.isMaster) { + var numCPUs = 1; + const paths = []; + var files = null; + var totalPaths = 0; + var failures = 0; + var successes = 0; + var lastLineLen = 0; + var curPath = 'Starting ...'; + var showProgress = true; + const globOptions = { + nodir: true + }; + const workerConfig = {}; + var startTime; + var formatter; + var outFn; + var fd; + var i; + + // Check if spreading work among all cores/cpus + if (process.argv.indexOf('-J') !== -1) + numCPUs = totalCPUs; + + // Check if spreading work among an explicit number of cores/cpus + i = process.argv.indexOf('-j'); + if (i !== -1) { + if (!process.argv[i + 1]) + throw new Error('Missing parallel job count'); + numCPUs = parseInt(process.argv[i + 1], 10); + if (!isFinite(numCPUs) || numCPUs <= 0) + throw new Error('Bad parallel job count'); + } + + // Check for custom JSLint report formatter + i = process.argv.indexOf('-f'); + if (i !== -1) { + if (!process.argv[i + 1]) + throw new Error('Missing format name'); + const format = process.argv[i + 1]; + formatter = cli.getFormatter(format); + if (!formatter) + throw new Error('Invalid format name'); + // Automatically disable progress display + showProgress = false; + // Tell worker to send all results, not just linter errors + workerConfig.sendAll = true; + } else { + // Use default formatter + formatter = cli.getFormatter(); + } + + // Check if outputting JSLint report to a file instead of stdout + i = process.argv.indexOf('-o'); + if (i !== -1) { + if (!process.argv[i + 1]) + throw new Error('Missing output filename'); + var outPath = process.argv[i + 1]; + if (!path.isAbsolute(outPath)) + outPath = path.join(cwd, outPath); + fd = fs.openSync(outPath, 'w'); + outFn = function(str) { + fs.writeSync(fd, str, 'utf8'); + }; + process.on('exit', function() { + fs.closeSync(fd); + }); + } else { + outFn = function(str) { + process.stdout.write(str); + }; + } + + // Process the rest of the arguments as paths to lint, ignoring any unknown + // flags + for (i = 2; i < process.argv.length; ++i) { + if (process.argv[i][0] === '-') { + switch (process.argv[i]) { + case '-f': // Skip format name + case '-o': // Skip filename + case '-j': // Skip parallel job count number + ++i; + break; + } + continue; + } + paths.push(process.argv[i]); + } + + if (paths.length === 0) + return; + totalPaths = paths.length; + + if (showProgress) { + // Start the progress display update timer when the first worker is ready + cluster.once('online', function(worker) { + startTime = process.hrtime(); + setInterval(printProgress, 1000).unref(); + printProgress(); + }); + } + + cluster.on('online', function(worker) { + // Configure worker and give it some initial work to do + worker.send(workerConfig); + sendWork(worker); + }); + + cluster.on('message', function(worker, results) { + if (typeof results !== 'number') { + // The worker sent us results that are not all successes + if (!workerConfig.sendAll) + failures += results.length; + outFn(formatter(results) + '\r\n'); + printProgress(); + } else { + successes += results; + } + // Try to give the worker more work to do + sendWork(worker); + }); + + process.on('exit', function() { + if (showProgress) { + curPath = 'Done'; + printProgress(); + outFn('\r\n'); + } + process.exit(failures ? 1 : 0); + }); + + for (i = 0; i < numCPUs; ++i) + cluster.fork(); + + function sendWork(worker) { + if (!files || !files.length) { + // We either just started or we have no more files to lint for the current + // path. Find the next path that has some files to be linted. + while (paths.length) { + var dir = paths.shift(); + curPath = dir; + if (dir.indexOf('/') > 0) + dir = path.join(cwd, dir); + const patterns = cli.resolveFileGlobPatterns([dir]); + dir = path.resolve(patterns[0]); + files = glob.sync(dir, globOptions); + if (files.length) + break; + } + if ((!files || !files.length) && !paths.length) { + // We exhausted all input paths and thus have nothing left to do, so end + // the worker + return worker.disconnect(); + } + } + // Give the worker an equal portion of the work left for the current path, + // but not exceeding a maximum file count in order to help keep *all* + // workers busy most of the time instead of only a minority doing most of + // the work. + const sliceLen = Math.min(maxWorkload, Math.ceil(files.length / numCPUs)); + var slice; + if (sliceLen === files.length) { + // Micro-ptimization to avoid splicing to an empty array + slice = files; + files = null; + } else { + slice = files.splice(0, sliceLen); + } + worker.send(slice); + } + + function printProgress() { + if (!showProgress) + return; + + // Clear line + outFn('\r' + ' '.repeat(lastLineLen) + '\r'); + + // Calculate and format the data for displaying + const elapsed = process.hrtime(startTime)[0]; + const mins = padString(Math.floor(elapsed / 60), 2, '0'); + const secs = padString(elapsed % 60, 2, '0'); + const passed = padString(successes, 6, ' '); + const failed = padString(failures, 6, ' '); + var pct = Math.ceil(((totalPaths - paths.length) / totalPaths) * 100); + pct = padString(pct, 3, ' '); + + var line = `[${mins}:${secs}|%${pct}|+${passed}|-${failed}]: ${curPath}`; + + // Truncate line like cpplint does in case it gets too long + if (line.length > 75) + line = line.slice(0, 75) + '...'; + + // Store the line length so we know how much to erase the next time around + lastLineLen = line.length; + + outFn(line); + } + + function padString(str, len, chr) { + str = '' + str; + if (str.length >= len) + return str; + return chr.repeat(len - str.length) + str; + } +} else { + // Worker + + var config = {}; + process.on('message', function(files) { + if (files instanceof Array) { + // Lint some files + const report = cli.executeOnFiles(files); + if (config.sendAll) { + // Return both success and error results + + const results = report.results; + // Silence warnings for files with no errors while keeping the "ok" + // status + if (report.warningCount > 0) { + for (var i = 0; i < results.length; ++i) { + const result = results[i]; + if (result.errorCount === 0 && result.warningCount > 0) { + result.warningCount = 0; + result.messages = []; + } + } + } + process.send(results); + } else if (report.errorCount === 0) { + // No errors, return number of successful lint operations + process.send(files.length); + } else { + // One or more errors, return the error results only + process.send(CLIEngine.getErrorResults(report.results)); + } + } else if (typeof files === 'object') { + // The master process is actually sending us our configuration and not a + // list of files to lint + config = files; + } + }); +} diff --git a/vcbuild.bat b/vcbuild.bat index 950bace411a..61cf3ff5549 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -66,6 +66,7 @@ if /i "%1"=="test-pummel" set test_args=%test_args% pummel&goto arg-ok if /i "%1"=="test-all" set test_args=%test_args% sequential parallel message gc internet pummel&set buildnodeweak=1&set jslint=1&goto arg-ok if /i "%1"=="test-known-issues" set test_args=%test_args% known_issues --expect-fail&goto arg-ok if /i "%1"=="jslint" set jslint=1&goto arg-ok +if /i "%1"=="jslint-ci" set jslint_ci=1&goto arg-ok if /i "%1"=="msi" set msi=1&set licensertf=1&set download_arg="--download=all"&set i18n_arg=small-icu&goto arg-ok if /i "%1"=="build-release" set build_release=1&goto arg-ok if /i "%1"=="upload" set upload=1&goto arg-ok @@ -286,10 +287,16 @@ python tools\test.py %test_args% goto jslint :jslint +if defined jslint_ci goto jslint-ci if not defined jslint goto exit if not exist tools\eslint\bin\eslint.js goto no-lint echo running jslint -%config%\node tools\eslint\bin\eslint.js benchmark lib src test tools\doc tools\eslint-rules --rulesdir tools\eslint-rules +%config%\node tools\jslint.js -J benchmark lib src test tools\doc tools\eslint-rules tools\jslint.js +goto exit + +:jslint-ci +echo running jslint-ci +%config%\node tools\jslint.js -J -f tap -o test-eslint.tap benchmark lib src test tools\doc tools\eslint-rules tools\jslint.js goto exit :no-lint From b488b19eaf2b2e7a3ca5eccd2445e245847a5f76 Mon Sep 17 00:00:00 2001 From: Yuval Brik Date: Mon, 11 Apr 2016 17:48:34 +0300 Subject: [PATCH 02/48] fs: optimize realpath using uv_fs_realpath() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove realpath() and realpathSync() cache. Use the native uv_fs_realpath() which is faster then the JS implementation by a few orders of magnitude. PR-URL: https://github.com/nodejs/node/pull/3594 Reviewed-By: Trevor Norris Reviewed-By: Brian White Reviewed-By: James M Snell Reviewed-By: Johan Bergström --- doc/api/fs.markdown | 36 ++-- lib/fs.js | 249 +++--------------------- lib/module.js | 13 +- src/node_file.cc | 52 +++++ test/parallel/test-fs-realpath.js | 99 +++------- test/sequential/test-regress-GH-3542.js | 14 +- 6 files changed, 134 insertions(+), 329 deletions(-) diff --git a/doc/api/fs.markdown b/doc/api/fs.markdown index 6fdea6f7f0e..fc2dd5934ec 100644 --- a/doc/api/fs.markdown +++ b/doc/api/fs.markdown @@ -916,26 +916,20 @@ object with an `encoding` property specifying the character encoding to use for the link path passed to the callback. If the `encoding` is set to `'buffer'`, the link path returned will be passed as a `Buffer` object. -## fs.realpath(path[, cache], callback) +## fs.realpath(path[, options], callback) * `path` {String | Buffer} -* `cache` {Object} +* `options` {String | Object} + * `encoding` {String} default = `'utf8'` * `callback` {Function} Asynchronous realpath(2). The `callback` gets two arguments `(err, -resolvedPath)`. May use `process.cwd` to resolve relative paths. `cache` is an -object literal of mapped paths that can be used to force a specific path -resolution or avoid additional `fs.stat` calls for known real paths. - -Example: +resolvedPath)`. May use `process.cwd` to resolve relative paths. -```js -var cache = {'/etc':'/private/etc'}; -fs.realpath('/etc/passwd', cache, (err, resolvedPath) => { - if (err) throw err; - console.log(resolvedPath); -}); -``` +The optional `options` argument can be a string specifying an encoding, or an +object with an `encoding` property specifying the character encoding to use for +the path passed to the callback. If the `encoding` is set to `'buffer'`, +the path returned will be passed as a `Buffer` object. ## fs.readSync(fd, buffer, offset, length, position) @@ -947,14 +941,18 @@ fs.realpath('/etc/passwd', cache, (err, resolvedPath) => { Synchronous version of [`fs.read()`][]. Returns the number of `bytesRead`. -## fs.realpathSync(path[, cache]) +## fs.realpathSync(path[, options]) * `path` {String | Buffer}; -* `cache` {Object} +* `options` {String | Object} + * `encoding` {String} default = `'utf8'` -Synchronous realpath(2). Returns the resolved path. `cache` is an -object literal of mapped paths that can be used to force a specific path -resolution or avoid additional `fs.stat` calls for known real paths. +Synchronous realpath(2). Returns the resolved path. + +The optional `options` argument can be a string specifying an encoding, or an +object with an `encoding` property specifying the character encoding to use for +the path passed to the callback. If the `encoding` is set to `'buffer'`, +the path returned will be passed as a `Buffer` object. ## fs.rename(oldPath, newPath, callback) diff --git a/lib/fs.js b/lib/fs.js index acb2676bb4c..3047e5ad98d 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -1557,234 +1557,37 @@ fs.unwatchFile = function(filename, listener) { } }; -// Regexp that finds the next partion of a (partial) path -// result is [base_with_slash, base], e.g. ['somedir/', 'somedir'] -const nextPartRe = isWindows ? - /(.*?)(?:[\/\\]+|$)/g : - /(.*?)(?:[\/]+|$)/g; - -// Regex to find the device root, including trailing slash. E.g. 'c:\\'. -const splitRootRe = isWindows ? - /^(?:[a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?[\\\/]*/ : - /^[\/]*/; - -fs.realpathSync = function realpathSync(p, cache) { - // make p is absolute - p = pathModule.resolve(p); - - if (cache && Object.prototype.hasOwnProperty.call(cache, p)) { - return cache[p]; - } - - const original = p; - const seenLinks = {}; - const knownHard = {}; - - // current character position in p - var pos; - // the partial path so far, including a trailing slash if any - var current; - // the partial path without a trailing slash (except when pointing at a root) - var base; - // the partial path scanned in the previous round, with slash - var previous; - - start(); - - function start() { - // Skip over roots - var m = splitRootRe.exec(p); - pos = m[0].length; - current = m[0]; - base = m[0]; - previous = ''; - - // On windows, check that the root exists. On unix there is no need. - if (isWindows && !knownHard[base]) { - fs.lstatSync(base); - knownHard[base] = true; - } - } - - // walk down the path, swapping out linked pathparts for their real - // values - // NB: p.length changes. - while (pos < p.length) { - // find the next part - nextPartRe.lastIndex = pos; - var result = nextPartRe.exec(p); - previous = current; - current += result[0]; - base = previous + result[1]; - pos = nextPartRe.lastIndex; - - // continue if not a symlink - if (knownHard[base] || (cache && cache[base] === base)) { - continue; - } - - var resolvedLink; - if (cache && Object.prototype.hasOwnProperty.call(cache, base)) { - // some known symbolic link. no need to stat again. - resolvedLink = cache[base]; - } else { - var stat = fs.lstatSync(base); - if (!stat.isSymbolicLink()) { - knownHard[base] = true; - if (cache) cache[base] = base; - continue; - } - - // read the link if it wasn't read before - // dev/ino always return 0 on windows, so skip the check. - var linkTarget = null; - if (!isWindows) { - var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); - if (seenLinks.hasOwnProperty(id)) { - linkTarget = seenLinks[id]; - } - } - if (linkTarget === null) { - fs.statSync(base); - linkTarget = fs.readlinkSync(base); - } - resolvedLink = pathModule.resolve(previous, linkTarget); - // track this, if given a cache. - if (cache) cache[base] = resolvedLink; - if (!isWindows) seenLinks[id] = linkTarget; - } - // resolve the link, then start over - p = pathModule.resolve(resolvedLink, p.slice(pos)); - start(); - } - - if (cache) cache[original] = p; - - return p; +fs.realpathSync = function realpathSync(path, options) { + if (!options) + options = {}; + else if (typeof options === 'string') + options = {encoding: options}; + else if (typeof options !== 'object') + throw new TypeError('"options" must be a string or an object'); + nullCheck(path); + return binding.realpath(pathModule._makeLong(path), options.encoding); }; -fs.realpath = function realpath(p, cache, cb) { - if (typeof cb !== 'function') { - cb = maybeCallback(cache); - cache = null; - } - - // make p is absolute - p = pathModule.resolve(p); - - if (cache && Object.prototype.hasOwnProperty.call(cache, p)) { - return process.nextTick(cb.bind(null, null, cache[p])); - } - - const original = p; - const seenLinks = {}; - const knownHard = {}; - - // current character position in p - var pos; - // the partial path so far, including a trailing slash if any - var current; - // the partial path without a trailing slash (except when pointing at a root) - var base; - // the partial path scanned in the previous round, with slash - var previous; - - start(); - - function start() { - // Skip over roots - var m = splitRootRe.exec(p); - pos = m[0].length; - current = m[0]; - base = m[0]; - previous = ''; - - // On windows, check that the root exists. On unix there is no need. - if (isWindows && !knownHard[base]) { - fs.lstat(base, function(err) { - if (err) return cb(err); - knownHard[base] = true; - LOOP(); - }); - } else { - process.nextTick(LOOP); - } - } - - // walk down the path, swapping out linked pathparts for their real - // values - function LOOP() { - // stop if scanned past end of path - if (pos >= p.length) { - if (cache) cache[original] = p; - return cb(null, p); - } - - // find the next part - nextPartRe.lastIndex = pos; - var result = nextPartRe.exec(p); - previous = current; - current += result[0]; - base = previous + result[1]; - pos = nextPartRe.lastIndex; - - // continue if not a symlink - if (knownHard[base] || (cache && cache[base] === base)) { - return process.nextTick(LOOP); - } - - if (cache && Object.prototype.hasOwnProperty.call(cache, base)) { - // known symbolic link. no need to stat again. - return gotResolvedLink(cache[base]); - } - - return fs.lstat(base, gotStat); - } - - function gotStat(err, stat) { - if (err) return cb(err); - - // if not a symlink, skip to the next path part - if (!stat.isSymbolicLink()) { - knownHard[base] = true; - if (cache) cache[base] = base; - return process.nextTick(LOOP); - } - - // stat & read the link if not read before - // call gotTarget as soon as the link target is known - // dev/ino always return 0 on windows, so skip the check. - if (!isWindows) { - var id = stat.dev.toString(32) + ':' + stat.ino.toString(32); - if (seenLinks.hasOwnProperty(id)) { - return gotTarget(null, seenLinks[id], base); - } - } - fs.stat(base, function(err) { - if (err) return cb(err); - - fs.readlink(base, function(err, target) { - if (!isWindows) seenLinks[id] = target; - gotTarget(err, target); - }); - }); - } - - function gotTarget(err, target, base) { - if (err) return cb(err); - - var resolvedLink = pathModule.resolve(previous, target); - if (cache) cache[base] = resolvedLink; - gotResolvedLink(resolvedLink); - } - - function gotResolvedLink(resolvedLink) { - // resolve the link, then start over - p = pathModule.resolve(resolvedLink, p.slice(pos)); - start(); +fs.realpath = function realpath(path, options, callback) { + if (!options) { + options = {}; + } else if (typeof options === 'function') { + callback = options; + options = {}; + } else if (typeof options === 'string') { + options = {encoding: options}; + } else if (typeof options !== 'object') { + throw new TypeError('"options" must be a string or an object'); } + callback = makeCallback(callback); + if (!nullCheck(path, callback)) + return; + var req = new FSReqWrap(); + req.oncomplete = callback; + binding.realpath(pathModule._makeLong(path), options.encoding, req); + return; }; diff --git a/lib/module.js b/lib/module.js index 8e5dc7a8182..29a23776d79 100644 --- a/lib/module.js +++ b/lib/module.js @@ -108,19 +108,10 @@ function tryPackage(requestPath, exts) { tryExtensions(path.resolve(filename, 'index'), exts); } -// In order to minimize unnecessary lstat() calls, -// this cache is a list of known-real paths. -// Set to an empty object to reset. -Module._realpathCache = {}; - // check if the file exists and is not a directory function tryFile(requestPath) { const rc = stat(requestPath); - return rc === 0 && toRealPath(requestPath); -} - -function toRealPath(requestPath) { - return fs.realpathSync(requestPath, Module._realpathCache); + return rc === 0 && fs.realpathSync(requestPath); } // given a path check a the file exists with any of the set extensions @@ -163,7 +154,7 @@ Module._findPath = function(request, paths) { if (!trailingSlash) { const rc = stat(basePath); if (rc === 0) { // File. - filename = toRealPath(basePath); + filename = fs.realpathSync(basePath); } else if (rc === 1) { // Directory. if (exts === undefined) exts = Object.keys(Module._extensions); diff --git a/src/node_file.cc b/src/node_file.cc index e63dd3fd37d..c1dd59b9b71 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -241,6 +241,22 @@ static void After(uv_fs_t *req) { } break; + case UV_FS_REALPATH: + link = StringBytes::Encode(env->isolate(), + static_cast(req->ptr), + req_wrap->encoding_); + if (link.IsEmpty()) { + argv[0] = UVException(env->isolate(), + UV_EINVAL, + req_wrap->syscall(), + "Invalid character encoding for link", + req->path, + req_wrap->data()); + } else { + argv[1] = link; + } + break; + case UV_FS_READ: // Buffer interface argv[1] = Integer::New(env->isolate(), req->result); @@ -863,6 +879,41 @@ static void MKDir(const FunctionCallbackInfo& args) { } } +static void RealPath(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + + const int argc = args.Length(); + + if (argc < 1) + return TYPE_ERROR("path required"); + + BufferValue path(env->isolate(), args[0]); + ASSERT_PATH(path) + + const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8); + + Local callback = Null(env->isolate()); + if (argc == 3) + callback = args[2]; + + if (callback->IsObject()) { + ASYNC_CALL(realpath, callback, encoding, *path); + } else { + SYNC_CALL(realpath, *path, *path); + const char* link_path = static_cast(SYNC_REQ.ptr); + Local rc = StringBytes::Encode(env->isolate(), + link_path, + encoding); + if (rc.IsEmpty()) { + return env->ThrowUVException(UV_EINVAL, + "realpath", + "Invalid character encoding for path", + *path); + } + args.GetReturnValue().Set(rc); + } +} + static void ReadDir(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); @@ -1432,6 +1483,7 @@ void InitFs(Local target, env->SetMethod(target, "writeBuffer", WriteBuffer); env->SetMethod(target, "writeBuffers", WriteBuffers); env->SetMethod(target, "writeString", WriteString); + env->SetMethod(target, "realpath", RealPath); env->SetMethod(target, "chmod", Chmod); env->SetMethod(target, "fchmod", FChmod); diff --git a/test/parallel/test-fs-realpath.js b/test/parallel/test-fs-realpath.js index aa397e51d16..b7eb5145089 100644 --- a/test/parallel/test-fs-realpath.js +++ b/test/parallel/test-fs-realpath.js @@ -10,9 +10,13 @@ var skipSymlinks = false; common.refreshTmpDir(); var root = '/'; +var assertEqualPath = assert.equal; if (common.isWindows) { // something like "C:\\" root = process.cwd().substr(0, 3); + assertEqualPath = function(path_left, path_right, message) { + assert.equal(path_left.toLowerCase(), path_right.toLowerCase(), message); + }; // On Windows, creating symlinks requires admin privileges. // We'll only try to run symlink test if we have enough privileges. @@ -96,9 +100,9 @@ function test_simple_relative_symlink(callback) { unlink.push(t[0]); }); var result = fs.realpathSync(entry); - assert.equal(result, path.resolve(expected)); + assertEqualPath(result, path.resolve(expected)); asynctest(fs.realpath, [entry], callback, function(err, result) { - assert.equal(result, path.resolve(expected)); + assertEqualPath(result, path.resolve(expected)); }); } @@ -122,9 +126,9 @@ function test_simple_absolute_symlink(callback) { unlink.push(t[0]); }); var result = fs.realpathSync(entry); - assert.equal(result, path.resolve(expected)); + assertEqualPath(result, path.resolve(expected)); asynctest(fs.realpath, [entry], callback, function(err, result) { - assert.equal(result, path.resolve(expected)); + assertEqualPath(result, path.resolve(expected)); }); } @@ -151,9 +155,9 @@ function test_deep_relative_file_symlink(callback) { unlink.push(linkPath1); unlink.push(entry); - assert.equal(fs.realpathSync(entry), path.resolve(expected)); + assertEqualPath(fs.realpathSync(entry), path.resolve(expected)); asynctest(fs.realpath, [entry], callback, function(err, result) { - assert.equal(result, path.resolve(expected)); + assertEqualPath(result, path.resolve(expected)); }); } @@ -178,10 +182,10 @@ function test_deep_relative_dir_symlink(callback) { unlink.push(linkPath1b); unlink.push(entry); - assert.equal(fs.realpathSync(entry), path.resolve(expected)); + assertEqualPath(fs.realpathSync(entry), path.resolve(expected)); asynctest(fs.realpath, [entry], callback, function(err, result) { - assert.equal(result, path.resolve(expected)); + assertEqualPath(result, path.resolve(expected)); }); } @@ -223,9 +227,9 @@ function test_cyclic_link_overprotection(callback) { try {fs.unlinkSync(link);} catch (ex) {} fs.symlinkSync(cycles, link, 'dir'); unlink.push(link); - assert.equal(fs.realpathSync(testPath), path.resolve(expected)); + assertEqualPath(fs.realpathSync(testPath), path.resolve(expected)); asynctest(fs.realpath, [testPath], callback, function(er, res) { - assert.equal(res, path.resolve(expected)); + assertEqualPath(res, path.resolve(expected)); }); } @@ -258,10 +262,10 @@ function test_relative_input_cwd(callback) { var origcwd = process.cwd(); process.chdir(entrydir); - assert.equal(fs.realpathSync(entry), path.resolve(expected)); + assertEqualPath(fs.realpathSync(entry), path.resolve(expected)); asynctest(fs.realpath, [entry], callback, function(err, result) { process.chdir(origcwd); - assert.equal(result, path.resolve(expected)); + assertEqualPath(result, path.resolve(expected)); return true; }); } @@ -311,9 +315,9 @@ function test_deep_symlink_mix(callback) { unlink.push(tmp('node-test-realpath-d2')); } var expected = tmpAbsDir + '/cycles/root.js'; - assert.equal(fs.realpathSync(entry), path.resolve(expected)); + assertEqualPath(fs.realpathSync(entry), path.resolve(expected)); asynctest(fs.realpath, [entry], callback, function(err, result) { - assert.equal(result, path.resolve(expected)); + assertEqualPath(result, path.resolve(expected)); return true; }); } @@ -325,10 +329,10 @@ function test_non_symlinks(callback) { var expected = tmpAbsDir + '/cycles/root.js'; var origcwd = process.cwd(); process.chdir(entrydir); - assert.equal(fs.realpathSync(entry), path.resolve(expected)); + assertEqualPath(fs.realpathSync(entry), path.resolve(expected)); asynctest(fs.realpath, [entry], callback, function(err, result) { process.chdir(origcwd); - assert.equal(result, path.resolve(expected)); + assertEqualPath(result, path.resolve(expected)); return true; }); } @@ -337,13 +341,13 @@ var upone = path.join(process.cwd(), '..'); function test_escape_cwd(cb) { console.log('test_escape_cwd'); asynctest(fs.realpath, ['..'], cb, function(er, uponeActual) { - assert.equal(upone, uponeActual, + assertEqualPath(upone, uponeActual, 'realpath("..") expected: ' + path.resolve(upone) + ' actual:' + uponeActual); }); } var uponeActual = fs.realpathSync('..'); -assert.equal(upone, uponeActual, +assertEqualPath(upone, uponeActual, 'realpathSync("..") expected: ' + path.resolve(upone) + ' actual:' + uponeActual); @@ -385,14 +389,14 @@ function test_up_multiple(cb) { var abedabeda = tmp('abedabeda'.split('').join('/')); var abedabeda_real = tmp('a'); - assert.equal(fs.realpathSync(abedabeda), abedabeda_real); - assert.equal(fs.realpathSync(abedabed), abedabed_real); + assertEqualPath(fs.realpathSync(abedabeda), abedabeda_real); + assertEqualPath(fs.realpathSync(abedabed), abedabed_real); fs.realpath(abedabeda, function(er, real) { if (er) throw er; - assert.equal(abedabeda_real, real); + assertEqualPath(abedabeda_real, real); fs.realpath(abedabed, function(er, real) { if (er) throw er; - assert.equal(abedabed_real, real); + assertEqualPath(abedabed_real, real); cb(); cleanup(); }); @@ -450,56 +454,14 @@ function test_abs_with_kids(cb) { var expectPath = root + '/a/b/c/x.txt'; var actual = fs.realpathSync(linkPath); // console.log({link:linkPath,expect:expectPath,actual:actual},'sync'); - assert.equal(actual, path.resolve(expectPath)); + assertEqualPath(actual, path.resolve(expectPath)); asynctest(fs.realpath, [linkPath], cb, function(er, actual) { // console.log({link:linkPath,expect:expectPath,actual:actual},'async'); - assert.equal(actual, path.resolve(expectPath)); + assertEqualPath(actual, path.resolve(expectPath)); cleanup(); }); } -function test_lying_cache_liar(cb) { - var n = 2; - - // this should not require *any* stat calls, since everything - // checked by realpath will be found in the cache. - console.log('test_lying_cache_liar'); - var cache = { '/foo/bar/baz/bluff' : '/foo/bar/bluff', - '/1/2/3/4/5/6/7' : '/1', - '/a' : '/a', - '/a/b' : '/a/b', - '/a/b/c' : '/a/b', - '/a/b/d' : '/a/b/d' }; - if (common.isWindows) { - var wc = {}; - Object.keys(cache).forEach(function(k) { - wc[ path.resolve(k) ] = path.resolve(cache[k]); - }); - cache = wc; - } - - var bluff = path.resolve('/foo/bar/baz/bluff'); - var rps = fs.realpathSync(bluff, cache); - assert.equal(cache[bluff], rps); - var nums = path.resolve('/1/2/3/4/5/6/7'); - var called = false; // no sync cb calling! - fs.realpath(nums, cache, function(er, rp) { - called = true; - assert.equal(cache[nums], rp); - if (--n === 0) cb(); - }); - assert(called === false); - - const test = path.resolve('/a/b/c/d'); - const expect = path.resolve('/a/b/d'); - var actual = fs.realpathSync(test, cache); - assert.equal(expect, actual); - fs.realpath(test, cache, function(er, actual) { - assert.equal(expect, actual); - if (--n === 0) cb(); - }); -} - // ---------------------------------------------------------------------------- var tests = [ @@ -515,7 +477,6 @@ var tests = [ test_non_symlinks, test_escape_cwd, test_abs_with_kids, - test_lying_cache_liar, test_up_multiple ]; var numtests = tests.length; @@ -532,10 +493,10 @@ function runNextTest(err) { } -assert.equal(root, fs.realpathSync('/')); +assertEqualPath(root, fs.realpathSync('/')); fs.realpath('/', function(err, result) { assert.equal(null, err); - assert.equal(root, result); + assertEqualPath(root, result); }); diff --git a/test/sequential/test-regress-GH-3542.js b/test/sequential/test-regress-GH-3542.js index 77b8cdd6981..c7e52113178 100644 --- a/test/sequential/test-regress-GH-3542.js +++ b/test/sequential/test-regress-GH-3542.js @@ -13,21 +13,21 @@ if (!common.isWindows) { function test(p) { var result = fs.realpathSync(p); - assert.strictEqual(result, path.resolve(p)); + assert.strictEqual(result.toLowerCase(), path.resolve(p).toLowerCase()); fs.realpath(p, function(err, result) { assert.ok(!err); - assert.strictEqual(result, path.resolve(p)); + assert.strictEqual(result.toLowerCase(), path.resolve(p).toLowerCase()); succeeded++; }); } -test('//localhost/c$/windows/system32'); -test('//localhost/c$/windows'); +test('//localhost/c$/Windows/System32'); +test('//localhost/c$/Windows'); test('//localhost/c$/'); -test('\\\\localhost\\c$'); -test('c:\\'); -test('c:'); +test('\\\\localhost\\c$\\'); +test('C:\\'); +test('C:'); test(process.env.windir); process.on('exit', function() { From 627524973a22c584fdd06c951fbe82364927a1ed Mon Sep 17 00:00:00 2001 From: James M Snell Date: Mon, 21 Mar 2016 12:38:08 -0700 Subject: [PATCH 03/48] buffer: add Buffer.allocUnsafeSlow(size) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Aligns the functionality of SlowBuffer with the new Buffer constructor API. Next step is to docs-only deprecate SlowBuffer. Replace the internal uses of SlowBuffer with `Buffer.allocUnsafeSlow(size)` PR-URL: https://github.com/nodejs/node/pull/5833 Reviewed-By: Сковорода Никита Андреевич Reviewed-By: Trevor Norris Reviewed-By: Sakthipriyan Vairamani --- benchmark/buffers/buffer-creation.js | 8 +++ doc/api/buffer.markdown | 94 +++++++++++++++++++++------- lib/buffer.js | 29 +++++++-- lib/fs.js | 5 +- test/parallel/test-buffer-alloc.js | 20 +++--- 5 files changed, 116 insertions(+), 40 deletions(-) diff --git a/benchmark/buffers/buffer-creation.js b/benchmark/buffers/buffer-creation.js index e0e64d6934d..d1acd2694e4 100644 --- a/benchmark/buffers/buffer-creation.js +++ b/benchmark/buffers/buffer-creation.js @@ -8,6 +8,7 @@ const bench = common.createBenchmark(main, { 'fast-alloc', 'fast-alloc-fill', 'fast-allocUnsafe', + 'slow-allocUnsafe', 'slow', 'buffer()'], len: [10, 1024, 2048, 4096, 8192], @@ -39,6 +40,13 @@ function main(conf) { } bench.end(n); break; + case 'slow-allocUnsafe': + bench.start(); + for (let i = 0; i < n * 1024; i++) { + Buffer.allocUnsafeSlow(len); + } + bench.end(n); + break; case 'slow': bench.start(); for (let i = 0; i < n * 1024; i++) { diff --git a/doc/api/buffer.markdown b/doc/api/buffer.markdown index ac5fab2191c..a035cd694dc 100644 --- a/doc/api/buffer.markdown +++ b/doc/api/buffer.markdown @@ -87,27 +87,30 @@ to one of these new APIs.* containing a *copy* of the provided string. * [`Buffer.alloc(size[, fill[, encoding]])`][buffer_alloc] returns a "filled" `Buffer` instance of the specified size. This method can be significantly - slower than [`Buffer.allocUnsafe(size)`][buffer_allocunsafe] but ensures that - newly created `Buffer` instances never contain old and potentially sensitive - data. -* [`Buffer.allocUnsafe(size)`][buffer_allocunsafe] returns a new `Buffer` of - the specified `size` whose content *must* be initialized using either - [`buf.fill(0)`][] or written to completely. + slower than [`Buffer.allocUnsafe(size)`][buffer_allocunsafe] but ensures + that newly created `Buffer` instances never contain old and potentially + sensitive data. +* [`Buffer.allocUnsafe(size)`][buffer_allocunsafe] and + [`Buffer.allocUnsafeSlow(size)`][buffer_allocunsafeslow] each return a + new `Buffer` of the specified `size` whose content *must* be initialized + using either [`buf.fill(0)`][] or written to completely. `Buffer` instances returned by `Buffer.allocUnsafe(size)` *may* be allocated -off a shared internal memory pool if the `size` is less than or equal to half -`Buffer.poolSize`. +off a shared internal memory pool if `size` is less than or equal to half +`Buffer.poolSize`. Instances returned by `Buffer.allocUnsafeSlow(size)` *never* +use the shared internal memory pool. ### The `--zero-fill-buffers` command line option Node.js can be started using the `--zero-fill-buffers` command line option to force all newly allocated `Buffer` and `SlowBuffer` instances created using -either `new Buffer(size)`, `Buffer.allocUnsafe(size)`, or -`new SlowBuffer(size)` to be *automatically zero-filled* upon creation. Use of -this flag *changes the default behavior* of these methods and *can have a -significant impact* on performance. Use of the `--zero-fill-buffers` option is -recommended only when absolutely necessary to enforce that newly allocated -`Buffer` instances cannot contain potentially sensitive data. +either `new Buffer(size)`, `Buffer.allocUnsafe(size)`, +`Buffer.allocUnsafeSlow(size)` or `new SlowBuffer(size)` to be *automatically +zero-filled* upon creation. Use of this flag *changes the default behavior* of +these methods and *can have a significant impact* on performance. Use of the +`--zero-fill-buffers` option is recommended only when absolutely necessary to +enforce that newly allocated `Buffer` instances cannot contain potentially +sensitive data. ``` $ node --zero-fill-buffers @@ -115,14 +118,14 @@ $ node --zero-fill-buffers ``` -### What makes `Buffer.allocUnsafe(size)` "unsafe"? +### What makes `Buffer.allocUnsafe(size)` and `Buffer.allocUnsafeSlow(size)` "unsafe"? -When calling `Buffer.allocUnsafe()`, the segment of allocated memory is -*uninitialized* (it is not zeroed-out). While this design makes the allocation -of memory quite fast, the allocated segment of memory might contain old data -that is potentially sensitive. Using a `Buffer` created by -`Buffer.allocUnsafe(size)` without *completely* overwriting the memory can -allow this old data to be leaked when the `Buffer` memory is read. +When calling `Buffer.allocUnsafe()` (and `Buffer.allocUnsafeSlow()`), the +segment of allocated memory is *uninitialized* (it is not zeroed-out). While +this design makes the allocation of memory quite fast, the allocated segment of +memory might contain old data that is potentially sensitive. Using a `Buffer` +created by `Buffer.allocUnsafe()` without *completely* overwriting the memory +can allow this old data to be leaked when the `Buffer` memory is read. While there are clear performance advantages to using `Buffer.allocUnsafe()`, extra care *must* be taken in order to avoid introducing security @@ -466,6 +469,52 @@ Buffer pool if `size` is less than or equal to half `Buffer.poolSize`. The difference is subtle but can be important when an application requires the additional performance that `Buffer.allocUnsafe(size)` provides. +### Class Method: Buffer.allocUnsafeSlow(size) + +* `size` {Number} + +Allocates a new *non-zero-filled* and non-pooled `Buffer` of `size` bytes. The +`size` must be less than or equal to the value of +`require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is +`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. If a `size` less than 0 +is specified, a zero-length `Buffer` will be created. + +The underlying memory for `Buffer` instances created in this way is *not +initialized*. The contents of the newly created `Buffer` are unknown and +*may contain sensitive data*. Use [`buf.fill(0)`][] to initialize such +`Buffer` instances to zeroes. + +When using `Buffer.allocUnsafe()` to allocate new `Buffer` instances, +allocations under 4KB are, by default, sliced from a single pre-allocated +`Buffer`. This allows applications to avoid the garbage collection overhead of +creating many individually allocated Buffers. This approach improves both +performance and memory usage by eliminating the need to track and cleanup as +many `Persistent` objects. + +However, in the case where a developer may need to retain a small chunk of +memory from a pool for an indeterminate amount of time, it may be appropriate +to create an un-pooled Buffer instance using `Buffer.allocUnsafeSlow()` then +copy out the relevant bits. + +```js +// need to keep around a few small chunks of memory +const store = []; + +socket.on('readable', () => { + const data = socket.read(); + // allocate for retained data + const sb = Buffer.allocUnsafeSlow(10); + // copy the data into the new allocation + data.copy(sb, 0, 0, 10); + store.push(sb); +}); +``` + +Use of `Buffer.allocUnsafeSlow()` should be used only as a last resort *after* +a developer has observed undue memory retention in their applications. + +A `TypeError` will be thrown if `size` is not a number. + ### Class Method: Buffer.byteLength(string[, encoding]) * `string` {String | Buffer | TypedArray | DataView | ArrayBuffer} @@ -1805,7 +1854,8 @@ console.log(buf); [buffer_from_buffer]: #buffer_class_method_buffer_from_buffer [buffer_from_arraybuf]: #buffer_class_method_buffer_from_arraybuffer [buffer_from_string]: #buffer_class_method_buffer_from_str_encoding -[buffer_allocunsafe]: #buffer_class_method_buffer_allocraw_size +[buffer_allocunsafe]: #buffer_class_method_buffer_allocunsafe_size +[buffer_allocunsafeslow]: #buffer_class_method_buffer_allocunsafeslow_size [buffer_alloc]: #buffer_class_method_buffer_alloc_size_fill_encoding [`TypedArray.from()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from [`DataView`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView diff --git a/lib/buffer.js b/lib/buffer.js index f672dae558d..1d0963bb509 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -133,13 +133,23 @@ Buffer.from = function(value, encodingOrOffset, length) { Object.setPrototypeOf(Buffer.prototype, Uint8Array.prototype); Object.setPrototypeOf(Buffer, Uint8Array); +function assertSize(size) { + if (typeof size !== 'number') { + const err = new TypeError('"size" argument must be a number'); + // The following hides the 'assertSize' method from the + // callstack. This is done simply to hide the internal + // details of the implementation from bleeding out to users. + Error.captureStackTrace(err, assertSize); + throw err; + } +} + /** * Creates a new filled Buffer instance. * alloc(size[, fill[, encoding]]) **/ Buffer.alloc = function(size, fill, encoding) { - if (typeof size !== 'number') - throw new TypeError('"size" argument must be a number'); + assertSize(size); if (size <= 0) return createBuffer(size); if (fill !== undefined) { @@ -161,11 +171,22 @@ Buffer.alloc = function(size, fill, encoding) { * instance. If `--zero-fill-buffers` is set, will zero-fill the buffer. **/ Buffer.allocUnsafe = function(size) { - if (typeof size !== 'number') - throw new TypeError('"size" argument must be a number'); + assertSize(size); return allocate(size); }; +/** + * Equivalent to SlowBuffer(num), by default creates a non-zero-filled + * Buffer instance that is not allocated off the pre-initialized pool. + * If `--zero-fill-buffers` is set, will zero-fill the buffer. + **/ +Buffer.allocUnsafeSlow = function(size) { + assertSize(size); + if (size > 0) + flags[kNoZeroFill] = 1; + return createBuffer(size); +}; + // If --zero-fill-buffers command line argument is set, a zero-filled // buffer is returned. function SlowBuffer(length) { diff --git a/lib/fs.js b/lib/fs.js index 3047e5ad98d..e441746366e 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -3,7 +3,6 @@ 'use strict'; -const SlowBuffer = require('buffer').SlowBuffer; const util = require('util'); const pathModule = require('path'); @@ -321,7 +320,7 @@ ReadFileContext.prototype.read = function() { var length; if (this.size === 0) { - buffer = this.buffer = SlowBuffer(kReadFileBufferLength); + buffer = this.buffer = Buffer.allocUnsafeSlow(kReadFileBufferLength); offset = 0; length = kReadFileBufferLength; } else { @@ -389,7 +388,7 @@ function readFileAfterStat(err, st) { return context.close(err); } - context.buffer = SlowBuffer(size); + context.buffer = Buffer.allocUnsafeSlow(size); context.read(); } diff --git a/test/parallel/test-buffer-alloc.js b/test/parallel/test-buffer-alloc.js index 733fa105043..131fcb112f5 100644 --- a/test/parallel/test-buffer-alloc.js +++ b/test/parallel/test-buffer-alloc.js @@ -3,7 +3,6 @@ var common = require('../common'); var assert = require('assert'); var Buffer = require('buffer').Buffer; -var SlowBuffer = require('buffer').SlowBuffer; // counter to ensure unique value is always copied var cntr = 0; @@ -428,7 +427,7 @@ for (let i = 0; i < Buffer.byteLength(utf8String); i++) { { // also from a non-pooled instance - const b = new SlowBuffer(5); + const b = Buffer.allocUnsafeSlow(5); const c = b.slice(0, 4); const d = c.slice(0, 2); assert.equal(c.parent, d.parent); @@ -1305,7 +1304,7 @@ assert.throws(function() { // try to slice a zero length Buffer // see https://github.com/joyent/node/issues/5881 - SlowBuffer(0).slice(0, 1); + Buffer.alloc(0).slice(0, 1); })(); // Regression test for #5482: should throw but not assert in C++ land. @@ -1336,7 +1335,7 @@ assert.throws(function() { }, RangeError); assert.throws(function() { - SlowBuffer((-1 >>> 0) + 1); + Buffer.allocUnsafeSlow((-1 >>> 0) + 1); }, RangeError); if (common.hasCrypto) { @@ -1435,14 +1434,13 @@ assert.throws(function() { }, regErrorMsg); -// Test prototype getters don't throw -assert.equal(Buffer.prototype.parent, undefined); -assert.equal(Buffer.prototype.offset, undefined); -assert.equal(SlowBuffer.prototype.parent, undefined); -assert.equal(SlowBuffer.prototype.offset, undefined); - - // Test that ParseArrayIndex handles full uint32 assert.throws(function() { Buffer.from(new ArrayBuffer(0), -1 >>> 0); }, /RangeError: 'offset' is out of bounds/); + +// Unpooled buffer (replaces SlowBuffer) +const ubuf = Buffer.allocUnsafeSlow(10); +assert(ubuf); +assert(ubuf.buffer); +assert.equal(ubuf.buffer.byteLength, 10); From 3fe204c7009c9f629dfbca03a7221c6b1384777b Mon Sep 17 00:00:00 2001 From: James M Snell Date: Mon, 21 Mar 2016 12:39:57 -0700 Subject: [PATCH 04/48] buffer: docs-only deprecate SlowBuffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the addition of `Buffer.allocUnsafeSlow(size)` `SlowBuffer` can be deprecated... but docs-only for now. PR-URL: https://github.com/nodejs/node/pull/5833 Reviewed-By: Сковорода Никита Андреевич Reviewed-By: Trevor Norris Reviewed-By: Sakthipriyan Vairamani --- doc/api/buffer.markdown | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/api/buffer.markdown b/doc/api/buffer.markdown index a035cd694dc..0f55664a346 100644 --- a/doc/api/buffer.markdown +++ b/doc/api/buffer.markdown @@ -1783,6 +1783,9 @@ Note that this is a property on the `buffer` module as returned by ## Class: SlowBuffer + Stability: 0 - Deprecated: Use + [`Buffer.allocUnsafeSlow(size)`][buffer_allocunsafeslow] instead. + Returns an un-pooled `Buffer`. In order to avoid the garbage collection overhead of creating many individually @@ -1813,6 +1816,9 @@ has observed undue memory retention in their applications. ### new SlowBuffer(size) + Stability: 0 - Deprecated: Use + [`Buffer.allocUnsafeSlow(size)`][buffer_allocunsafeslow] instead. + * `size` Number Allocates a new `SlowBuffer` of `size` bytes. The `size` must be less than From a0579c0dc79aa8fab56638844f233b821a51b9e9 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Tue, 12 Apr 2016 10:40:56 -0700 Subject: [PATCH 05/48] doc: minor copy improvement in buffer.markdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/5833 Reviewed-By: Сковорода Никита Андреевич Reviewed-By: Trevor Norris Reviewed-By: Sakthipriyan Vairamani --- doc/api/buffer.markdown | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/doc/api/buffer.markdown b/doc/api/buffer.markdown index 0f55664a346..7153cb4ac6b 100644 --- a/doc/api/buffer.markdown +++ b/doc/api/buffer.markdown @@ -103,14 +103,13 @@ use the shared internal memory pool. ### The `--zero-fill-buffers` command line option Node.js can be started using the `--zero-fill-buffers` command line option to -force all newly allocated `Buffer` and `SlowBuffer` instances created using -either `new Buffer(size)`, `Buffer.allocUnsafe(size)`, -`Buffer.allocUnsafeSlow(size)` or `new SlowBuffer(size)` to be *automatically -zero-filled* upon creation. Use of this flag *changes the default behavior* of -these methods and *can have a significant impact* on performance. Use of the -`--zero-fill-buffers` option is recommended only when absolutely necessary to -enforce that newly allocated `Buffer` instances cannot contain potentially -sensitive data. +force all newly allocated `Buffer` instances created using either +`new Buffer(size)`, `Buffer.allocUnsafe(size)`, `Buffer.allocUnsafeSlow(size)` +or `new SlowBuffer(size)` to be *automatically zero-filled* upon creation. Use +of this flag *changes the default behavior* of these methods and *can have a +significant impact* on performance. Use of the `--zero-fill-buffers` option is +recommended only when absolutely necessary to enforce that newly allocated +`Buffer` instances cannot contain potentially sensitive data. ``` $ node --zero-fill-buffers @@ -342,8 +341,8 @@ console.log(buf); Allocates a new `Buffer` of `size` bytes. The `size` must be less than or equal to the value of `require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is `(2^31)-1`). Otherwise, a [`RangeError`][] is -thrown. If a `size` less than 0 is specified, a zero-length Buffer will be -created. +thrown. A zero-length Buffer will be created if a `size` less than or equal to +0 is specified. Unlike `ArrayBuffers`, the underlying memory for `Buffer` instances created in this way is *not initialized*. The contents of a newly created `Buffer` are @@ -400,8 +399,8 @@ console.log(buf); The `size` must be less than or equal to the value of `require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is -`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. If a `size` less than 0 -is specified, a zero-length `Buffer` will be created. +`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. A zero-length Buffer will +be created if a `size` less than or equal to 0 is specified. If `fill` is specified, the allocated `Buffer` will be initialized by calling `buf.fill(fill)`. See [`buf.fill()`][] for more information. @@ -434,8 +433,8 @@ A `TypeError` will be thrown if `size` is not a number. Allocates a new *non-zero-filled* `Buffer` of `size` bytes. The `size` must be less than or equal to the value of `require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is `(2^31)-1`). Otherwise, a [`RangeError`][] is -thrown. If a `size` less than 0 is specified, a zero-length `Buffer` will be -created. +thrown. A zero-length Buffer will be created if a `size` less than or equal to +0 is specified. The underlying memory for `Buffer` instances created in this way is *not initialized*. The contents of the newly created `Buffer` are unknown and @@ -476,8 +475,8 @@ additional performance that `Buffer.allocUnsafe(size)` provides. Allocates a new *non-zero-filled* and non-pooled `Buffer` of `size` bytes. The `size` must be less than or equal to the value of `require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is -`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. If a `size` less than 0 -is specified, a zero-length `Buffer` will be created. +`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. A zero-length Buffer will +be created if a `size` less than or equal to 0 is specified. The underlying memory for `Buffer` instances created in this way is *not initialized*. The contents of the newly created `Buffer` are unknown and @@ -1824,8 +1823,8 @@ has observed undue memory retention in their applications. Allocates a new `SlowBuffer` of `size` bytes. The `size` must be less than or equal to the value of `require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is `(2^31)-1`). Otherwise, a [`RangeError`][] is -thrown. If a `size` less than 0 is specified, a zero-length `SlowBuffer` will be -created. +thrown. A zero-length Buffer will be created if a `size` less than or equal to +0 is specified. The underlying memory for `SlowBuffer` instances is *not initialized*. The contents of a newly created `SlowBuffer` are unknown and could contain From 69040d6e955a94cdcd6a325e5b6b231f83365df2 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 15 Apr 2016 19:27:55 +0200 Subject: [PATCH 06/48] doc: add addaleax to collaborators PR-URL: https://github.com/nodejs/node/pull/6224 Reviewed-By: James M Snell Reviewed-By: Evan Lucas Reviewed-By: Rich Trott Reviewed-By: Ben Noordhuis Reviewed-By: Myles Borins --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 20c24dee60b..64183ca27da 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,7 @@ information about the governance of the Node.js project, see ### Collaborators +* [addaleax](https://github.com/addaleax) - **Anna Henningsen** <anna@addaleax.net> * [AndreasMadsen](https://github.com/AndreasMadsen) - **Andreas Madsen** <amwebdk@gmail.com> * [benjamingr](https://github.com/benjamingr) - **Benjamin Gruenbaum** <benjamingr@gmail.com> * [brendanashworth](https://github.com/brendanashworth) - **Brendan Ashworth** <brendan.ashworth@me.com> From 0f0711601683e1e4170b9e56153703b040429628 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 15 Apr 2016 19:32:52 +0200 Subject: [PATCH 07/48] doc: add santigimeno to collaborators PR-URL: https://github.com/nodejs/node/pull/6225 Reviewed-By: Ben Noordhuis Reviewed-By: Evan Lucas Reviewed-By: Rich Trott Reviewed-By: James M Snell Reviewed-By: Myles Borins --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 64183ca27da..6b3062c0e70 100644 --- a/README.md +++ b/README.md @@ -197,6 +197,7 @@ information about the governance of the Node.js project, see * [romankl](https://github.com/romankl) - **Roman Klauke** <romaaan.git@gmail.com> * [saghul](https://github.com/saghul) - **Saúl Ibarra Corretgé** <saghul@gmail.com> * [sam-github](https://github.com/sam-github) - **Sam Roberts** <vieuxtech@gmail.com> +* [santigimeno](https://github.com/santigimeno) - **Santiago Gimeno** <santiago.gimeno@gmail.com> * [seishun](https://github.com/seishun) - **Nikolai Vavilov** <vvnicholas@gmail.com> * [silverwind](https://github.com/silverwind) - **Roman Reiss** <me@silverwind.io> * [srl295](https://github.com/srl295) - **Steven R Loomis** <srloomis@us.ibm.com> From 0bf9a7c758c80d370b9c57f65800196c083bfc38 Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Fri, 15 Apr 2016 13:38:44 -0400 Subject: [PATCH 08/48] doc: add iWuzHere to collaborators PR-URL: https://github.com/nodejs/node/pull/6226 Reviewed-By: Evan Lucas Reviewed-By: Rich Trott --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6b3062c0e70..a6a77ad0172 100644 --- a/README.md +++ b/README.md @@ -177,6 +177,7 @@ information about the governance of the Node.js project, see * [geek](https://github.com/geek) - **Wyatt Preul** <wpreul@gmail.com> * [iarna](https://github.com/iarna) - **Rebecca Turner** <me@re-becca.org> * [isaacs](https://github.com/isaacs) - **Isaac Z. Schlueter** <i@izs.me> +* [iWuzHere](https://github.com/iWuzHere) - **Imran Iqbal** <imran@imraniqbal.org> * [jbergstroem](https://github.com/jbergstroem) - **Johan Bergström** <bugs@bergstroem.nu> * [joaocgreis](https://github.com/joaocgreis) - **João Reis** <reis@janeasystems.com> * [julianduque](https://github.com/julianduque) - **Julian Duque** <julianduquej@gmail.com> From 8c48a26459ef47114986e7b136d844053a9172a1 Mon Sep 17 00:00:00 2001 From: Stefan Budeanu Date: Fri, 15 Apr 2016 13:37:13 -0400 Subject: [PATCH 09/48] doc: add stefanmb to collaborators PR-URL: https://github.com/nodejs/node/pull/6227 Reviewed-By: Evan Lucas Reviewed-By: Rich Trott Reviewed-By: Myles Borins --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a6a77ad0172..99113d55e87 100644 --- a/README.md +++ b/README.md @@ -202,6 +202,7 @@ information about the governance of the Node.js project, see * [seishun](https://github.com/seishun) - **Nikolai Vavilov** <vvnicholas@gmail.com> * [silverwind](https://github.com/silverwind) - **Roman Reiss** <me@silverwind.io> * [srl295](https://github.com/srl295) - **Steven R Loomis** <srloomis@us.ibm.com> +* [stefanmb](https://github.com/stefanmb) - **Stefan Budeanu** <stefan@budeanu.com> * [targos](https://github.com/targos) - **Michaël Zasso** <mic.besace@gmail.com> * [tellnes](https://github.com/tellnes) - **Christian Tellnes** <christian@tellnes.no> * [thealphanerd](https://github.com/thealphanerd) - **Myles Borins** <myles.borins@gmail.com> From 4a74fc9776d825115849997f4adacb46f4303494 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Mon, 11 Apr 2016 16:28:41 -0600 Subject: [PATCH 10/48] doc: add domain postmortem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do to various reasons, outlined in the committed document, domains were only in core for 2 years before being deprecated. This outline explains why they received criticism from the community and never gained traction with module authors. Also included is an example script that accompanies the postmortem analysis. PR-URL: https://github.com/nodejs/node/pull/6159 Reviewed-By: Robert Lindstädt Reviewed-By: Kelvin Knighton Reviewed-By: James M Snell Reviewed-By: Jeremiah Senkpiel Reviewed-By: Benjamin Gruenbaum Reviewed-By: Brian White --- doc/topics/domain-postmortem.md | 299 ++++++++++++++++++ doc/topics/domain-resource-cleanup-example.js | 136 ++++++++ 2 files changed, 435 insertions(+) create mode 100644 doc/topics/domain-postmortem.md create mode 100644 doc/topics/domain-resource-cleanup-example.js diff --git a/doc/topics/domain-postmortem.md b/doc/topics/domain-postmortem.md new file mode 100644 index 00000000000..0a8a854a586 --- /dev/null +++ b/doc/topics/domain-postmortem.md @@ -0,0 +1,299 @@ +# Domain Module Postmortem + +## Usability Issues + +### Implicit Behavior + +It's possible for a developer to create a new domain and then simply run +`domain.enter()`. Which then acts as a catch-all for any exception in the +future that couldn't be observed by the thrower. Allowing a module author to +intercept the exceptions of unrelated code in a different module. Preventing +the originator of the code from knowing about its own exceptions. + +Here's an example of how one indirectly linked modules can affect another: + +```js +// module a.js +const b = require('./b'); +const c = require('./c'); + + +// module b.js +const d = require('domain').create(); +d.on('error', () => { /* silence everything */ }); +d.enter(); + + +// module c.js +const dep = require('some-dep'); +dep.method(); // Uh-oh! This method doesn't actually exist. +``` + +Since module `b` enters the domain but never exits any uncaught exception will +be swallowed. Leaving module `c` in the dark as to why it didn't run the entire +script. Leaving a potentially partially populated `module.exports`. Doing this +is not the same as listening for `'uncaughtException'`. As the latter is +explicitly meant to globally catch errors. The other issue is that domains are +processed prior to any `'uncaughtException'` handlers, and prevent them from +running. + +Another issue is that domains route errors automatically if no `'error'` +handler was set on the event emitter. There is no opt-in mechanism for this, +and automatically propagates across the entire asynchronous chain. This may +seem useful at first, but once asynchronous calls are two or more modules deep +and one of them doesn't include an error handler the creator of the domain will +suddenly be catching unexpected exceptions, and the thrower's exception will go +unnoticed by the author. + +The following is a simple example of how a missing `'error'` handler allows +the active domain to hijack the error: + +```js +const domain = require('domain'); +const net = require('net'); +const d = domain.create(); +d.on('error', (err) => console.error(err.message)); + +d.run(() => net.createServer((c) => { + c.end(); + c.write('bye'); +}).listen(8000)); +``` + +Even manually removing the connection via `d.remove(c)` does not prevent the +connection's error from being automatically intercepted. + +Failures that plagues both error routing and exception handling are the +inconsistencies in how errors are bubbled. The following is an example of how +nested domains will and won't bubble the exception based on when they happen: + +```js +const domain = require('domain'); +const net = require('net'); +const d = domain.create(); +d.on('error', () => console.error('d intercepted an error')); + +d.run(() => { + const server = net.createServer((c) => { + const e = domain.create(); // No 'error' handler being set. + e.run(() => { + // This will not be caught by d's error handler. + setImmediate(() => { + throw new Error('thrown from setImmediate'); + }); + // Though this one will bubble to d's error handler. + throw new Error('immediately thrown'); + }); + }).listen(8080); +}); +``` + +It may be expected that nested domains always remain nested, and will always +propagate the exception up the domain stack. Or that exceptions will never +automatically bubble. Unfortunately both these situations occur, leading to +potentially confusing behavior that may even be prone to difficult to debug +timing conflicts. + + +### API Gaps + +While APIs based on using `EventEmitter` can use `bind()` and errback style +callbacks can use `intercept()`, alternative APIs that implicitly bind to the +active domain must be executed inside of `run()`. Meaning if module authors +wanted to support domains using a mechanism alternative to those mentioned they +must manually implement domain support themselves. Instead of being able to +leverage the implicit mechanisms already in place. + + +### Error Propagation + +Propagating errors across nested domains is not straight forward, if even +possible. Existing documentation shows a simple example of how to `close()` an +`http` server if there is an error in the request handler. What it does not +explain is how to close the server if the request handler creates another +domain instance for another async request. Using the following as a simple +example of the failing of error propagation: + +```js +const d1 = domain.create(); +d1.foo = true; // custom member to make more visible in console +d1.on('error', (er) => { /* handle error */ }); + +d1.run(() => setTimeout(() => { + const d2 = domain.create(); + d2.bar = 43; + d2.on('error', (er) => console.error(er.message, domain._stack)); + d2.run(() => { + setTimeout(() => { + setTimeout(() => { + throw new Error('outer'); + }); + throw new Error('inner') + }); + }); +})); +``` + +Even in the case that the domain instances are being used for local storage so +access to resources are made available there is still no way to allow the error +to continue propagating from `d2` back to `d1`. Quick inspection may tell us +that simply throwing from `d2`'s domain `'error'` handler would allow `d1` to +then catch the exception and execute its own error handler. Though that is not +the case. Upon inspection of `domain._stack` you'll see that the stack only +contains `d2`. + +This may be considered a failing of the API, but even if it did operate in this +way there is still the issue of transmitting the fact that a branch in the +asynchronous execution has failed, and that all further operations in that +branch must cease. In the example of the http request handler, if we fire off +several asynchronous requests and each one then `write()`'s data back to the +client many more errors will arise from attempting to `write()` to a closed +handle. More on this in _Resource Cleanup on Exception_. + + +### Resource Cleanup on Exception + +The script [`domain-resource-cleanup.js`](domain-resource-cleanup.js) +contains a more complex example of properly cleaning up in a small resource +dependency tree in the case that an exception occurs in a given connection or +any of its dependencies. Breaking down the script into its basic operations: + +- When a new connection happens, concurrently: + - Open a file on the file system + - Open Pipe to unique socket +- Read a chunk of the file asynchronously +- Write chunk to both the TCP connection and any listening sockets +- If any of these resources error, notify all other attached resources that + they need to clean up and shutdown + +As we can see from this example a lot more must be done to properly clean up +resources when something fails than what can be done strictly through the +domain API. All that domains offer is an exception aggregation mechanism. Even +the potentially useful ability to propagate data with the domain is easily +countered, in this example, by passing the needed resources as a function +argument. + +One problem domains perpetuated was the supposed simplicity of being able to +continue execution, contrary to what the documentation stated, of the +application despite an unexpected exception. This example demonstrates the +fallacy behind that idea. + +Attempting proper resource cleanup on unexpected exception becomes more complex +as the application itself grows in complexity. This example only has 3 basic +resources in play, and all of them with a clear dependency path. If an +application uses something like shared resources or resource reuse the ability +to cleanup, and properly test that cleanup has been done, grows greatly. + +In the end, in terms of handling errors, domains aren't much more than a +glorified `'uncaughtException'` handler. Except with more implicit and +unobservable behavior by third-parties. + + +### Resource Propagation + +Another use case for domains was to use it to propagate data along asynchronous +data paths. One problematic point is the ambiguity of when to expect the +correct domain when there are multiple in the stack (which must be assumed if +the async stack works with other modules). Also the conflict between being +able to depend on a domain for error handling while also having it available to +retrieve the necessary data. + +The following is a involved example demonstrating the failing using domains to +propagate data along asynchronous stacks: + +```js +const domain = require('domain'); +const net = require('net'); + +const server = net.createServer((c) => { + // Use a domain to propagate data across events within the + // connection so that we don't have to pass arguments + // everywhere. + const d = domain.create(); + d.data = { connection: c }; + d.add(c); + // Mock class that does some useless async data transformation + // for demonstration purposes. + const ds = new DataStream(dataTransformed); + c.on('data', (chunk) => ds.data(chunk)); +}).listen(8080, () => console.log(`listening on 8080`)); + +function dataTransformed(chunk) { + // FAIL! Because the DataStream instance also created a + // domain we have now lost the active domain we had + // hoped to use. + domain.active.data.connection.write(chunk); +} + +function DataStream(cb) { + this.cb = cb; + // DataStream wants to use domains for data propagation too! + // Unfortunately this will conflict with any domain that + // already exists. + this.domain = domain.create(); + this.domain.data = { inst: this }; +} + +DataStream.prototype.data = function data(chunk) { + // This code is self contained, but pretend it's a complex + // operation that crosses at least one other module. So + // passing along "this", etc., is not easy. + this.domain.run(function() { + // Simulate an async operation that does the data transform. + setImmediate(() => { + for (var i = 0; i < chunk.length; i++) + chunk[i] = ((chunk[i] + Math.random() * 100) % 96) + 33; + // Grab the instance from the active domain and use that + // to call the user's callback. + const self = domain.active.data.inst; + self.cb.call(self, chunk); + }); + }); +}; +``` + +The above shows that it is difficult to have more than one asynchronous API +attempt to use domains to propagate data. This example could possibly be fixed +by assigning `parent: domain.active` in the `DataStream` constructor. Then +restoring it via `domain.active = domain.active.data.parent` just before the +user's callback is called. Also the instantiation of `DataStream` in the +`'connection'` callback must be run inside `d.run()`, instead of simply using +`d.add(c)`, otherwise there will be no active domain. + +In short, for this to have a prayer of a chance usage would need to strictly +adhere to a set of guidelines that would be difficult to enforce or test. + + +## Performance Issues + +A significant deterrent from using domains is the overhead. Using node's +built-in http benchmark, `http_simple.js`, without domains it can handle over +22,000 requests/second. Whereas if it's run with `NODE_USE_DOMAINS=1` that +number drops down to under 17,000 requests/second. In this case there is only +a single global domain. If we edit the benchmark so the http request callback +creates a new domain instance performance drops further to 15,000 +requests/second. + +While this probably wouldn't affect a server only serving a few hundred or even +a thousand requests per second, the amount of overhead is directly proportional +to the number of asynchronous requests made. So if a single connection needs to +connect to several other services all of those will contribute to the overall +latency of delivering the final product to the client. + +Using `AsyncWrap` and tracking the number of times +`init`/`pre`/`post`/`destroy` are called in the mentioned benchmark we find +that the sum of all events called is over 170,000 times per second. This means +even adding 1 microsecond overhead per call for any type of setup or tear down +will result in a 17% performance loss. Granted, this is for the optimized +scenario of the benchmark, but I believe this demonstrates the necessity for a +mechanism such as domain to be as cheap to run as possible. + + +## Looking Ahead + +The domain module has been soft deprecated since Dec 2014, but has not yet been +removed because node offers no alternative functionality at the moment. As of +this writing there is ongoing work building out the `AsyncWrap` API and a +proposal for Zones being prepared for the TC39. At such time there is suitable +functionality to replace domains it will undergo the full deprecation cycle and +eventually be removed from core. diff --git a/doc/topics/domain-resource-cleanup-example.js b/doc/topics/domain-resource-cleanup-example.js new file mode 100644 index 00000000000..d379d1a00e6 --- /dev/null +++ b/doc/topics/domain-resource-cleanup-example.js @@ -0,0 +1,136 @@ +'use strict'; + +const domain = require('domain'); +const EE = require('events'); +const fs = require('fs'); +const net = require('net'); +const util = require('util'); +const print = process._rawDebug; + +const pipeList = []; +const FILENAME = '/tmp/tmp.tmp'; +const PIPENAME = '/tmp/node-domain-example-'; +const FILESIZE = 1024; +var uid = 0; + +// Setting up temporary resources +const buf = Buffer(FILESIZE); +for (var i = 0; i < buf.length; i++) + buf[i] = ((Math.random() * 1e3) % 78) + 48; // Basic ASCII +fs.writeFileSync(FILENAME, buf); + +function ConnectionResource(c) { + EE.call(this); + this._connection = c; + this._alive = true; + this._domain = domain.create(); + this._id = Math.random().toString(32).substr(2).substr(0, 8) + (++uid); + + this._domain.add(c); + this._domain.on('error', () => { + this._alive = false; + }); +} +util.inherits(ConnectionResource, EE); + +ConnectionResource.prototype.end = function end(chunk) { + this._alive = false; + this._connection.end(chunk); + this.emit('end'); +}; + +ConnectionResource.prototype.isAlive = function isAlive() { + return this._alive; +}; + +ConnectionResource.prototype.id = function id() { + return this._id; +}; + +ConnectionResource.prototype.write = function write(chunk) { + this.emit('data', chunk); + return this._connection.write(chunk); +}; + +// Example begin +net.createServer((c) => { + const cr = new ConnectionResource(c); + + const d1 = domain.create(); + fs.open(FILENAME, 'r', d1.intercept((fd) => { + streamInParts(fd, cr, 0); + })); + + pipeData(cr); + + c.on('close', () => cr.end()); +}).listen(8080); + +function streamInParts(fd, cr, pos) { + const d2 = domain.create(); + var alive = true; + d2.on('error', (er) => { + print('d2 error:', er.message) + cr.end(); + }); + fs.read(fd, new Buffer(10), 0, 10, pos, d2.intercept((bRead, buf) => { + if (!cr.isAlive()) { + return fs.close(fd); + } + if (cr._connection.bytesWritten < FILESIZE) { + // Documentation says callback is optional, but doesn't mention that if + // the write fails an exception will be thrown. + const goodtogo = cr.write(buf); + if (goodtogo) { + setTimeout(() => streamInParts(fd, cr, pos + bRead), 1000); + } else { + cr._connection.once('drain', () => streamInParts(fd, cr, pos + bRead)); + } + return; + } + cr.end(buf); + fs.close(fd); + })); +} + +function pipeData(cr) { + const pname = PIPENAME + cr.id(); + const ps = net.createServer(); + const d3 = domain.create(); + const connectionList = []; + d3.on('error', (er) => { + print('d3 error:', er.message); + cr.end(); + }); + d3.add(ps); + ps.on('connection', (conn) => { + connectionList.push(conn); + conn.on('data', () => {}); // don't care about incoming data. + conn.on('close', () => { + connectionList.splice(connectionList.indexOf(conn), 1); + }); + }); + cr.on('data', (chunk) => { + for (var i = 0; i < connectionList.length; i++) { + connectionList[i].write(chunk); + } + }); + cr.on('end', () => { + for (var i = 0; i < connectionList.length; i++) { + connectionList[i].end(); + } + ps.close(); + }); + pipeList.push(pname); + ps.listen(pname); +} + +process.on('SIGINT', () => process.exit()); +process.on('exit', () => { + try { + for (var i = 0; i < pipeList.length; i++) { + fs.unlinkSync(pipeList[i]); + } + fs.unlinkSync(FILENAME); + } catch (e) { } +}); From f49a1d050178cbaab7732e8643c4db33c4b81ede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Bergstr=C3=B6m?= Date: Fri, 15 Apr 2016 12:15:40 +0900 Subject: [PATCH 11/48] build: allow test-ci to run tests in parallel Run tests in parallel if the environment variable JOBS (which should contain a number of parallel jobs) is set. PR-URL: https://github.com/nodejs/node/pull/6208 Reviewed-By: Rod Vagg Reviewed-By: Myles Borins Reviewed-By: Rich Trott Reviewed-By: Ben Noordhuis --- Makefile | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 36681212673..1edbb789291 100644 --- a/Makefile +++ b/Makefile @@ -8,9 +8,12 @@ PREFIX ?= /usr/local FLAKY_TESTS ?= run TEST_CI_ARGS ?= STAGINGSERVER ?= node-www - OSTYPE := $(shell uname -s | tr '[A-Z]' '[a-z]') +ifdef JOBS + PARALLEL_ARGS = -j $(JOBS) +endif + ifdef QUICKCHECK QUICKCHECK_ARG := --quickcheck endif @@ -168,7 +171,8 @@ test-all-valgrind: test-build $(PYTHON) tools/test.py --mode=debug,release --valgrind test-ci: | build-addons - $(PYTHON) tools/test.py -p tap --logfile test.tap --mode=release --flaky-tests=$(FLAKY_TESTS) \ + $(PYTHON) tools/test.py $(PARALLEL_ARGS) -p tap --logfile test.tap \ + --mode=release --flaky-tests=$(FLAKY_TESTS) \ $(TEST_CI_ARGS) addons message parallel sequential test-release: test-build @@ -607,8 +611,9 @@ jslint: tools/eslint-rules tools/jslint.js jslint-ci: - $(NODE) tools/jslint.js -f tap -o test-eslint.tap benchmark lib src test \ - tools/doc tools/eslint-rules tools/jslint.js + $(NODE) tools/jslint.js $(PARALLEL_ARGS) -f tap -o test-eslint.tap \ + benchmark lib src test tools/doc \ + tools/eslint-rules tools/jslint.js CPPLINT_EXCLUDE ?= CPPLINT_EXCLUDE += src/node_lttng.cc From 978166796edb5a867a9152f8a2a1ae35899e4000 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Wed, 6 Apr 2016 00:54:34 +0200 Subject: [PATCH 12/48] zlib: Make the finish flush flag configurable Up to now, `Z_FINISH` was always the flushing flag that was used for the last chunk of input data. This patch makes this choice configurable so that advanced users can perform e.g. decompression of partial data using `Z_SYNC_FLUSH`, if that suits their needs. Add tests to make sure that an error is thrown upon encountering invalid `flush` or `finishFlush` flags. Fixes: https://github.com/nodejs/node/issues/5761 PR-URL: https://github.com/nodejs/node/pull/6069 Reviewed-By: James M Snell --- doc/api/zlib.markdown | 26 +++++++++++++++++++++ lib/zlib.js | 32 ++++++++++++++++---------- test/parallel/test-zlib-flush-flags.js | 28 ++++++++++++++++++++++ test/parallel/test-zlib-truncated.js | 17 ++++++++++++++ 4 files changed, 91 insertions(+), 12 deletions(-) create mode 100644 test/parallel/test-zlib-flush-flags.js diff --git a/doc/api/zlib.markdown b/doc/api/zlib.markdown index da20024ca21..92f3f5e52c4 100644 --- a/doc/api/zlib.markdown +++ b/doc/api/zlib.markdown @@ -109,6 +109,31 @@ http.createServer((request, response) => { }).listen(1337); ``` +By default, the zlib methods with throw an error when decompressing +truncated data. However, if it is known that the data is incomplete, or +the desire is to inspect only the beginning of a compressed file, it is +possible to suppress the default error handling by changing the flushing +method that is used to compressed the last chunk of input data: + +```js +// This is a truncated version of the buffer from the above examples +const buffer = new Buffer('eJzT0yMA', 'base64'); + +zlib.unzip(buffer, { finishFlush: zlib.Z_SYNC_FLUSH }, (err, buffer) => { + if (!err) { + console.log(buffer.toString()); + } else { + // handle error + } +}); +``` + +This will not change the behavior in other error-throwing situations, e.g. +when the input data has an invalid format. Using this method, it will not be +possible to determine whether the input ended prematurely or lacks the +integrity checks, making it necessary to manually check that the +decompressed result is valid. + ## Memory Usage Tuning @@ -231,6 +256,7 @@ Note that some options are only relevant when compressing, and are ignored by the decompression classes. * flush (default: `zlib.Z_NO_FLUSH`) +* finishFlush (default: `zlib.Z_FINISH`) * chunkSize (default: 16*1024) * windowBits * level (compression only) diff --git a/lib/zlib.js b/lib/zlib.js index 79c78ea4a51..a786a0c9118 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -234,7 +234,7 @@ function zlibBufferSync(engine, buffer) { if (!(buffer instanceof Buffer)) throw new TypeError('Not a string or buffer'); - var flushFlag = binding.Z_FINISH; + var flushFlag = engine._finishFlushFlag; return engine._processChunk(buffer, flushFlag); } @@ -282,6 +282,14 @@ function Unzip(opts) { Zlib.call(this, opts, binding.UNZIP); } +function isValidFlushFlag(flag) { + return flag === binding.Z_NO_FLUSH || + flag === binding.Z_PARTIAL_FLUSH || + flag === binding.Z_SYNC_FLUSH || + flag === binding.Z_FULL_FLUSH || + flag === binding.Z_FINISH || + flag === binding.Z_BLOCK; +} // the Zlib class they all inherit from // This thing manages the queue of requests, and returns @@ -294,17 +302,16 @@ function Zlib(opts, mode) { Transform.call(this, opts); - if (opts.flush) { - if (opts.flush !== binding.Z_NO_FLUSH && - opts.flush !== binding.Z_PARTIAL_FLUSH && - opts.flush !== binding.Z_SYNC_FLUSH && - opts.flush !== binding.Z_FULL_FLUSH && - opts.flush !== binding.Z_FINISH && - opts.flush !== binding.Z_BLOCK) { - throw new Error('Invalid flush flag: ' + opts.flush); - } + if (opts.flush && !isValidFlushFlag(opts.flush)) { + throw new Error('Invalid flush flag: ' + opts.flush); } + if (opts.finishFlush && !isValidFlushFlag(opts.finishFlush)) { + throw new Error('Invalid flush flag: ' + opts.finishFlush); + } + this._flushFlag = opts.flush || binding.Z_NO_FLUSH; + this._finishFlushFlag = typeof opts.finishFlush !== 'undefined' ? + opts.finishFlush : binding.Z_FINISH; if (opts.chunkSize) { if (opts.chunkSize < exports.Z_MIN_CHUNK || @@ -486,12 +493,13 @@ Zlib.prototype._transform = function(chunk, encoding, cb) { if (this._closed) return cb(new Error('zlib binding closed')); - // If it's the last chunk, or a final flush, we use the Z_FINISH flush flag. + // If it's the last chunk, or a final flush, we use the Z_FINISH flush flag + // (or whatever flag was provided using opts.finishFlush). // If it's explicitly flushing at some other time, then we use // Z_FULL_FLUSH. Otherwise, use Z_NO_FLUSH for maximum compression // goodness. if (last) - flushFlag = binding.Z_FINISH; + flushFlag = this._finishFlushFlag; else { flushFlag = this._flushFlag; // once we've flushed the last of the queue, stop flushing and diff --git a/test/parallel/test-zlib-flush-flags.js b/test/parallel/test-zlib-flush-flags.js new file mode 100644 index 00000000000..08c79f138b5 --- /dev/null +++ b/test/parallel/test-zlib-flush-flags.js @@ -0,0 +1,28 @@ +'use strict'; +require('../common'); +const assert = require('assert'); +const zlib = require('zlib'); + +assert.doesNotThrow(() => { + zlib.createGzip({ flush: zlib.Z_SYNC_FLUSH }); +}); + +assert.throws(() => { + zlib.createGzip({ flush: 'foobar' }); +}, /Invalid flush flag: foobar/); + +assert.throws(() => { + zlib.createGzip({ flush: 10000 }); +}, /Invalid flush flag: 10000/); + +assert.doesNotThrow(() => { + zlib.createGzip({ finishFlush: zlib.Z_SYNC_FLUSH }); +}); + +assert.throws(() => { + zlib.createGzip({ finishFlush: 'foobar' }); +}, /Invalid flush flag: foobar/); + +assert.throws(() => { + zlib.createGzip({ finishFlush: 10000 }); +}, /Invalid flush flag: 10000/); diff --git a/test/parallel/test-zlib-truncated.js b/test/parallel/test-zlib-truncated.js index 38888b68be7..1798a2ca974 100644 --- a/test/parallel/test-zlib-truncated.js +++ b/test/parallel/test-zlib-truncated.js @@ -45,5 +45,22 @@ const inputString = 'ΩΩLorem ipsum dolor sit amet, consectetur adipiscing el' zlib[methods.decomp](truncated, function(err, result) { assert(/unexpected end of file/.test(err.message)); }); + + const syncFlushOpt = { finishFlush: zlib.Z_SYNC_FLUSH }; + + // sync truncated input test, finishFlush = Z_SYNC_FLUSH + assert.doesNotThrow(function() { + const result = zlib[methods.decompSync](truncated, syncFlushOpt) + .toString(); + assert.equal(result, inputString.substr(0, result.length)); + }); + + // async truncated input test, finishFlush = Z_SYNC_FLUSH + zlib[methods.decomp](truncated, syncFlushOpt, function(err, decompressed) { + assert.ifError(err); + + const result = decompressed.toString(); + assert.equal(result, inputString.substr(0, result.length)); + }); }); }); From 15f13cd74a8bb9e62b871076328447b4ead7e8b6 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Thu, 14 Apr 2016 20:34:24 -0700 Subject: [PATCH 13/48] test,vm: enable strict mode for vm tests Some vm tests are not in strict mode because they need to create and use global variables. By using `global.foo` instead of just `foo`, we can still enable strict mode. PR-URL: https://github.com/nodejs/node/pull/6209 Reviewed-By: James M Snell Reviewed-By: Ben Noordhuis Reviewed-By: Jeremiah Senkpiel Reviewed-By: Santiago Gimeno Reviewed-By: Minwoo Jung --- .../test-vm-new-script-new-context.js | 40 +++++++++---------- .../test-vm-new-script-this-context.js | 36 ++++++++--------- test/parallel/test-vm-run-in-new-context.js | 36 ++++++++--------- 3 files changed, 56 insertions(+), 56 deletions(-) diff --git a/test/parallel/test-vm-new-script-new-context.js b/test/parallel/test-vm-new-script-new-context.js index 81f9b57593e..2af8f05f1c5 100644 --- a/test/parallel/test-vm-new-script-new-context.js +++ b/test/parallel/test-vm-new-script-new-context.js @@ -1,15 +1,15 @@ -/* eslint-disable strict */ -var common = require('../common'); -var assert = require('assert'); -var Script = require('vm').Script; +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const Script = require('vm').Script; common.globalCheck = false; console.error('run a string'); var script = new Script('\'passed\';'); console.error('script created'); -var result1 = script.runInNewContext(); -var result2 = script.runInNewContext(); +const result1 = script.runInNewContext(); +const result2 = script.runInNewContext(); assert.equal('passed', result1); assert.equal('passed', result2); @@ -27,31 +27,31 @@ assert.throws(function() { }, /not defined/); -hello = 5; +global.hello = 5; script = new Script('hello = 2'); script.runInNewContext(); -assert.equal(5, hello); +assert.equal(5, global.hello); console.error('pass values in and out'); -code = 'foo = 1;' + - 'bar = 2;' + - 'if (baz !== 3) throw new Error(\'test fail\');'; -foo = 2; -obj = { foo: 0, baz: 3 }; -script = new Script(code); +global.code = 'foo = 1;' + + 'bar = 2;' + + 'if (baz !== 3) throw new Error(\'test fail\');'; +global.foo = 2; +global.obj = { foo: 0, baz: 3 }; +script = new Script(global.code); /* eslint-disable no-unused-vars */ -var baz = script.runInNewContext(obj); +var baz = script.runInNewContext(global.obj); /* eslint-enable no-unused-vars */ -assert.equal(1, obj.foo); -assert.equal(2, obj.bar); -assert.equal(2, foo); +assert.equal(1, global.obj.foo); +assert.equal(2, global.obj.bar); +assert.equal(2, global.foo); console.error('call a function by reference'); script = new Script('f()'); -function changeFoo() { foo = 100; } +function changeFoo() { global.foo = 100; } script.runInNewContext({ f: changeFoo }); -assert.equal(foo, 100); +assert.equal(global.foo, 100); console.error('modify an object by reference'); script = new Script('f.a = 2'); diff --git a/test/parallel/test-vm-new-script-this-context.js b/test/parallel/test-vm-new-script-this-context.js index 16d8acd1ca6..d225fb0d402 100644 --- a/test/parallel/test-vm-new-script-this-context.js +++ b/test/parallel/test-vm-new-script-this-context.js @@ -1,13 +1,13 @@ -/* eslint-disable strict */ -var common = require('../common'); -var assert = require('assert'); -var Script = require('vm').Script; +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const Script = require('vm').Script; common.globalCheck = false; console.error('run a string'); var script = new Script('\'passed\';'); -var result = script.runInThisContext(script); +const result = script.runInThisContext(script); assert.equal('passed', result); console.error('thrown error'); @@ -16,26 +16,26 @@ assert.throws(function() { script.runInThisContext(script); }); -hello = 5; +global.hello = 5; script = new Script('hello = 2'); script.runInThisContext(script); -assert.equal(2, hello); +assert.equal(2, global.hello); console.error('pass values'); -code = 'foo = 1;' + - 'bar = 2;' + - 'if (typeof baz !== \'undefined\') throw new Error(\'test fail\');'; -foo = 2; -obj = { foo: 0, baz: 3 }; -script = new Script(code); +global.code = 'foo = 1;' + + 'bar = 2;' + + 'if (typeof baz !== "undefined") throw new Error("test fail");'; +global.foo = 2; +global.obj = { foo: 0, baz: 3 }; +script = new Script(global.code); script.runInThisContext(script); -assert.equal(0, obj.foo); -assert.equal(2, bar); -assert.equal(1, foo); +assert.equal(0, global.obj.foo); +assert.equal(2, global.bar); +assert.equal(1, global.foo); console.error('call a function'); -f = function() { foo = 100; }; +global.f = function() { global.foo = 100; }; script = new Script('f()'); script.runInThisContext(script); -assert.equal(100, foo); +assert.equal(100, global.foo); diff --git a/test/parallel/test-vm-run-in-new-context.js b/test/parallel/test-vm-run-in-new-context.js index 2b32eccf408..1467ea1e17d 100644 --- a/test/parallel/test-vm-run-in-new-context.js +++ b/test/parallel/test-vm-run-in-new-context.js @@ -1,16 +1,16 @@ -/* eslint-disable strict */ +'use strict'; // Flags: --expose-gc -var common = require('../common'); -var assert = require('assert'); -var vm = require('vm'); +const common = require('../common'); +const assert = require('assert'); +const vm = require('vm'); assert.equal(typeof gc, 'function', 'Run this test with --expose-gc'); common.globalCheck = false; console.error('run a string'); -var result = vm.runInNewContext('\'passed\';'); +const result = vm.runInNewContext('\'passed\';'); assert.equal('passed', result); console.error('thrown error'); @@ -18,28 +18,28 @@ assert.throws(function() { vm.runInNewContext('throw new Error(\'test\');'); }); -hello = 5; +global.hello = 5; vm.runInNewContext('hello = 2'); -assert.equal(5, hello); +assert.equal(5, global.hello); console.error('pass values in and out'); -code = 'foo = 1;' + - 'bar = 2;' + - 'if (baz !== 3) throw new Error(\'test fail\');'; -foo = 2; -obj = { foo: 0, baz: 3 }; +global.code = 'foo = 1;' + + 'bar = 2;' + + 'if (baz !== 3) throw new Error(\'test fail\');'; +global.foo = 2; +global.obj = { foo: 0, baz: 3 }; /* eslint-disable no-unused-vars */ -var baz = vm.runInNewContext(code, obj); +var baz = vm.runInNewContext(global.code, global.obj); /* eslint-enable no-unused-vars */ -assert.equal(1, obj.foo); -assert.equal(2, obj.bar); -assert.equal(2, foo); +assert.equal(1, global.obj.foo); +assert.equal(2, global.obj.bar); +assert.equal(2, global.foo); console.error('call a function by reference'); -function changeFoo() { foo = 100; } +function changeFoo() { global.foo = 100; } vm.runInNewContext('f()', { f: changeFoo }); -assert.equal(foo, 100); +assert.equal(global.foo, 100); console.error('modify an object by reference'); var f = { a: 1 }; From 642076f2aff3cddf93dd7cb6b1a332f8064ab39f Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 15 Apr 2016 19:40:01 +0200 Subject: [PATCH 14/48] src: don't set non-primitive values on templates V8 is going to disallow non-primitive values on v8::FunctionTemplate and v8::ObjectTemplate because those can't be shared across contexts. Fixes: https://github.com/nodejs/node/issues/6216 PR-URL: https://github.com/nodejs/node/pull/6228 Reviewed-By: Trevor Norris --- lib/_http_common.js | 10 ++++++---- src/env-inl.h | 14 ++++++-------- src/node.h | 21 ++++++++++++++++----- src/node_http_parser.cc | 2 +- test/parallel/test-http-parser.js | 6 +++--- 5 files changed, 32 insertions(+), 21 deletions(-) diff --git a/lib/_http_common.js b/lib/_http_common.js index 08f93d8c4d0..7c9fac5c6b7 100644 --- a/lib/_http_common.js +++ b/lib/_http_common.js @@ -1,8 +1,10 @@ 'use strict'; -const FreeList = require('internal/freelist').FreeList; -const HTTPParser = process.binding('http_parser').HTTPParser; +const binding = process.binding('http_parser'); +const methods = binding.methods; +const HTTPParser = binding.HTTPParser; +const FreeList = require('internal/freelist').FreeList; const incoming = require('_http_incoming'); const IncomingMessage = incoming.IncomingMessage; const readStart = incoming.readStart; @@ -14,7 +16,7 @@ exports.debug = debug; exports.CRLF = '\r\n'; exports.chunkExpression = /chunk/i; exports.continueExpression = /100-continue/i; -exports.methods = HTTPParser.methods; +exports.methods = methods; const kOnHeaders = HTTPParser.kOnHeaders | 0; const kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0; @@ -71,7 +73,7 @@ function parserOnHeadersComplete(versionMajor, versionMinor, headers, method, if (typeof method === 'number') { // server only - parser.incoming.method = HTTPParser.methods[method]; + parser.incoming.method = methods[method]; } else { // client only parser.incoming.statusCode = statusCode; diff --git a/src/env-inl.h b/src/env-inl.h index 475e8e83f59..2c6248ae608 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -507,27 +507,25 @@ inline void Environment::SetProtoMethod(v8::Local that, const char* name, v8::FunctionCallback callback) { v8::Local signature = v8::Signature::New(isolate(), that); - v8::Local function = - NewFunctionTemplate(callback, signature)->GetFunction(); + v8::Local t = NewFunctionTemplate(callback, signature); // kInternalized strings are created in the old space. const v8::NewStringType type = v8::NewStringType::kInternalized; v8::Local name_string = v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked(); - that->PrototypeTemplate()->Set(name_string, function); - function->SetName(name_string); // NODE_SET_PROTOTYPE_METHOD() compatibility. + that->PrototypeTemplate()->Set(name_string, t); + t->SetClassName(name_string); // NODE_SET_PROTOTYPE_METHOD() compatibility. } inline void Environment::SetTemplateMethod(v8::Local that, const char* name, v8::FunctionCallback callback) { - v8::Local function = - NewFunctionTemplate(callback)->GetFunction(); + v8::Local t = NewFunctionTemplate(callback); // kInternalized strings are created in the old space. const v8::NewStringType type = v8::NewStringType::kInternalized; v8::Local name_string = v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked(); - that->Set(name_string, function); - function->SetName(name_string); // NODE_SET_METHOD() compatibility. + that->Set(name_string, t); + t->SetClassName(name_string); // NODE_SET_METHOD() compatibility. } inline v8::Local Environment::NewInternalFieldObject() { diff --git a/src/node.h b/src/node.h index 59df8e18b4f..529ee75f279 100644 --- a/src/node.h +++ b/src/node.h @@ -240,8 +240,20 @@ NODE_EXTERN void RunAtExit(Environment* env); while (0) // Used to be a macro, hence the uppercase name. -template -inline void NODE_SET_METHOD(const TypeName& recv, +inline void NODE_SET_METHOD(v8::Local recv, + const char* name, + v8::FunctionCallback callback) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handle_scope(isolate); + v8::Local t = v8::FunctionTemplate::New(isolate, + callback); + v8::Local fn_name = v8::String::NewFromUtf8(isolate, name); + t->SetClassName(fn_name); + recv->Set(fn_name, t); +} + +// Used to be a macro, hence the uppercase name. +inline void NODE_SET_METHOD(v8::Local recv, const char* name, v8::FunctionCallback callback) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); @@ -265,10 +277,9 @@ inline void NODE_SET_PROTOTYPE_METHOD(v8::Local recv, v8::Local s = v8::Signature::New(isolate, recv); v8::Local t = v8::FunctionTemplate::New(isolate, callback, v8::Local(), s); - v8::Local fn = t->GetFunction(); - recv->PrototypeTemplate()->Set(v8::String::NewFromUtf8(isolate, name), fn); v8::Local fn_name = v8::String::NewFromUtf8(isolate, name); - fn->SetName(fn_name); + t->SetClassName(fn_name); + recv->PrototypeTemplate()->Set(v8::String::NewFromUtf8(isolate, name), t); } #define NODE_SET_PROTOTYPE_METHOD node::NODE_SET_PROTOTYPE_METHOD diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index 4087ed263fb..7d30cfd99ee 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -759,7 +759,7 @@ void InitHttpParser(Local target, methods->Set(num, FIXED_ONE_BYTE_STRING(env->isolate(), #string)); HTTP_METHOD_MAP(V) #undef V - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "methods"), methods); + target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "methods"), methods); env->SetProtoMethod(t, "close", Parser::Close); env->SetProtoMethod(t, "execute", Parser::Execute); diff --git a/test/parallel/test-http-parser.js b/test/parallel/test-http-parser.js index 6c1466c4184..b5bf275a6df 100644 --- a/test/parallel/test-http-parser.js +++ b/test/parallel/test-http-parser.js @@ -2,14 +2,14 @@ require('../common'); var assert = require('assert'); -var HTTPParser = process.binding('http_parser').HTTPParser; +const binding = process.binding('http_parser'); +const methods = binding.methods; +const HTTPParser = binding.HTTPParser; var CRLF = '\r\n'; var REQUEST = HTTPParser.REQUEST; var RESPONSE = HTTPParser.RESPONSE; -var methods = HTTPParser.methods; - var kOnHeaders = HTTPParser.kOnHeaders | 0; var kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0; var kOnBody = HTTPParser.kOnBody | 0; From b95160daae00a5c39b3815c29a0cfcbc395e3824 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 15 Apr 2016 15:38:04 +0200 Subject: [PATCH 15/48] test: move the debugger tests back to parallel Run the debugger with `--port=common.PORT` to avoid the use of the same port. PR-URL: https://github.com/nodejs/node/pull/6246 Reviewed-By: Rich Trott Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig --- test/{sequential => parallel}/test-debugger-repeat-last.js | 1 + test/{sequential => parallel}/test-debugger-util-regression.js | 1 + 2 files changed, 2 insertions(+) rename test/{sequential => parallel}/test-debugger-repeat-last.js (97%) rename test/{sequential => parallel}/test-debugger-util-regression.js (98%) diff --git a/test/sequential/test-debugger-repeat-last.js b/test/parallel/test-debugger-repeat-last.js similarity index 97% rename from test/sequential/test-debugger-repeat-last.js rename to test/parallel/test-debugger-repeat-last.js index 7f0e1e68165..666a7bca743 100644 --- a/test/sequential/test-debugger-repeat-last.js +++ b/test/parallel/test-debugger-repeat-last.js @@ -12,6 +12,7 @@ const fixture = path.join( const args = [ 'debug', + `--port=${common.PORT}`, fixture ]; diff --git a/test/sequential/test-debugger-util-regression.js b/test/parallel/test-debugger-util-regression.js similarity index 98% rename from test/sequential/test-debugger-util-regression.js rename to test/parallel/test-debugger-util-regression.js index cf32ec3fa66..a2461a480c9 100644 --- a/test/sequential/test-debugger-util-regression.js +++ b/test/parallel/test-debugger-util-regression.js @@ -12,6 +12,7 @@ const fixture = path.join( const args = [ 'debug', + `--port=${common.PORT}`, fixture ]; From 88c35e70a06d1d048cc32153d8214bcd28107528 Mon Sep 17 00:00:00 2001 From: Joran Dirk Greef Date: Thu, 7 Apr 2016 14:36:39 +0200 Subject: [PATCH 16/48] doc: clarify fs.watch() and inodes on linux, os x On Linux and OS X systems, `fs.watch()` resolves the watched path to an inode. This clarifies that `fs.watch()` watches the inode and not the path. If the inode of the path subsequently changes, `fs.watch()` will continue watching the original inode and events for the path will no longer be emitted. This is expected behavior. Fixes: https://github.com/nodejs/node/issues/5039 PR-URL: https://github.com/nodejs/node/pull/6099 Reviewed-By: James M Snell --- doc/api/fs.markdown | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/api/fs.markdown b/doc/api/fs.markdown index fc2dd5934ec..8a05ffa3c23 100644 --- a/doc/api/fs.markdown +++ b/doc/api/fs.markdown @@ -1155,6 +1155,16 @@ reliably or at all. You can still use `fs.watchFile`, which uses stat polling, but it is slower and less reliable. +#### Inodes + + + +On Linux and OS X systems, `fs.watch()` resolves the path to an [inode][] and +watches the inode. If the watched path is deleted and recreated, it is assigned +a new inode. The watch will emit an event for the delete but will continue +watching the *original* inode. Events for the new inode will not be emitted. +This is expected behavior. + #### Filename Argument @@ -1376,3 +1386,4 @@ Synchronous versions of [`fs.write()`][]. Returns the number of bytes written. [MDN-Date]: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date [Readable Stream]: stream.html#stream_class_stream_readable [Writable Stream]: stream.html#stream_class_stream_writable +[inode]: http://www.linux.org/threads/intro-to-inodes.4130 From eafd31a4eb028e1566c2384e710eb5397f5490e5 Mon Sep 17 00:00:00 2001 From: Alexander Makarenko Date: Sat, 20 Feb 2016 03:07:00 +0300 Subject: [PATCH 17/48] tools,doc: parse types in braces everywhere Also add `EvalError`, `RangeError`, `ReferenceError`, `SyntaxError`, `TypeError`, `URIError` to list of global types. Fix errors.markdown copy accordingly. Fixes: https://github.com/nodejs/node/issues/5325. PR-URL: https://github.com/nodejs/node/pull/5329 Reviewed-By: James M Snell --- doc/api/errors.markdown | 29 ++++++++++------------------- tools/doc/html.js | 6 ++---- tools/doc/type-parser.js | 3 ++- 3 files changed, 14 insertions(+), 24 deletions(-) diff --git a/doc/api/errors.markdown b/doc/api/errors.markdown index 810a8b7e367..2d4ba89e00a 100644 --- a/doc/api/errors.markdown +++ b/doc/api/errors.markdown @@ -6,13 +6,13 @@ Applications running in Node.js will generally experience four categories of errors: - Standard JavaScript errors such as: - - [`EvalError`][]: thrown when a call to `eval()` fails. - - [`SyntaxError`][]: thrown in response to improper JavaScript language + - {EvalError} : thrown when a call to `eval()` fails. + - {SyntaxError} : thrown in response to improper JavaScript language syntax. - - [`RangeError`][]: thrown when a value is not within an expected range - - [`ReferenceError`][]: thrown when using undefined variables - - [`TypeError`][]: thrown when passing arguments of the wrong type - - [`URIError`][]: thrown when a global URI handling function is misused. + - {RangeError} : thrown when a value is not within an expected range + - {ReferenceError} : thrown when using undefined variables + - {TypeError} : thrown when passing arguments of the wrong type + - {URIError} : thrown when a global URI handling function is misused. - System errors triggered by underlying operating system constraints such as attempting to open a file that does not exist, attempting to send data over a closed socket, etc; @@ -22,7 +22,7 @@ errors: are raised typically by the `assert` module. All JavaScript and System errors raised by Node.js inherit from, or are -instances of, the standard JavaScript [`Error`][] class and are guaranteed +instances of, the standard JavaScript {Error} class and are guaranteed to provide *at least* the properties available on that class. ## Error Propagation and Interception @@ -36,7 +36,7 @@ called. All JavaScript errors are handled as exceptions that *immediately* generate and throw an error using the standard JavaScript `throw` mechanism. These -are handled using the [`try / catch` construct][] provided by the JavaScript +are handled using the [`try / catch` construct][try-catch] provided by the JavaScript language. ```js @@ -105,7 +105,7 @@ pass or fail). For *all* `EventEmitter` objects, if an `'error'` event handler is not provided, the error will be thrown, causing the Node.js process to report an -unhandled exception and crash unless either: The [`domain`][] module is used +unhandled exception and crash unless either: The [`domain`][domains] module is used appropriately or a handler has been registered for the [`process.on('uncaughtException')`][] event. @@ -520,9 +520,6 @@ found [here][online]. encountered by [`http`][] or [`net`][] -- often a sign that a `socket.end()` was not properly called. -[`domain`]: domain.html -[`EvalError`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/EvalError -[`Error`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error [`fs.readdir`]: fs.html#fs_fs_readdir_path_callback [`fs.readFileSync`]: fs.html#fs_fs_readfilesync_file_options [`fs.unlink`]: fs.html#fs_fs_unlink_path_callback @@ -531,18 +528,12 @@ found [here][online]. [`https`]: https.html [`net`]: net.html [`process.on('uncaughtException')`]: process.html#process_event_uncaughtexception -[`try / catch` construct]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch -[`try { } catch(err) { }`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch [domains]: domain.html [event emitter-based]: events.html#events_class_events_eventemitter [file descriptors]: https://en.wikipedia.org/wiki/File_descriptor [online]: http://man7.org/linux/man-pages/man3/errno.3.html [stream-based]: stream.html [syscall]: http://man7.org/linux/man-pages/man2/syscall.2.html +[try-catch]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch [V8's stack trace API]: https://github.com/v8/v8/wiki/Stack-Trace-API [vm]: vm.html -[`SyntaxError`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError -[`RangeError`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError -[`ReferenceError`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError -[`TypeError`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError -[`URIError`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/URIError diff --git a/tools/doc/html.js b/tools/doc/html.js index 327c9f080e2..feb99cd8104 100644 --- a/tools/doc/html.js +++ b/tools/doc/html.js @@ -112,6 +112,7 @@ function parseText(lexed) { lexed.forEach(function(tok) { if (tok.text && tok.type !== 'code') { tok.text = linkManPages(tok.text); + tok.text = linkJsTypeDocs(tok.text); } }); } @@ -166,9 +167,6 @@ function parseLists(input) { } return; } - if (tok.text) { - tok.text = parseListItem(tok.text); - } } output.push(tok); }); @@ -197,7 +195,7 @@ function linkManPages(text) { }); } -function parseListItem(text) { +function linkJsTypeDocs(text) { var parts = text.split('`'); var i; var typeMatches; diff --git a/tools/doc/type-parser.js b/tools/doc/type-parser.js index 4d83e872ec1..2e6c5bea919 100644 --- a/tools/doc/type-parser.js +++ b/tools/doc/type-parser.js @@ -11,7 +11,8 @@ const jsGlobalTypes = [ 'Error', 'Object', 'Function', 'Array', 'Uint8Array', 'Uint16Array', 'Uint32Array', 'Int8Array', 'Int16Array', 'Int32Array', 'Uint8ClampedArray', 'Float32Array', 'Float64Array', 'Date', 'RegExp', - 'ArrayBuffer', 'DataView', 'Promise' + 'ArrayBuffer', 'DataView', 'Promise', 'EvalError', 'RangeError', + 'ReferenceError', 'SyntaxError', 'TypeError', 'URIError' ]; const typeMap = { 'Buffer': 'buffer.html#buffer_class_buffer', From b7f4b1ba4cca320cf576aa73fae15902fd801190 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Thu, 14 Apr 2016 20:51:04 -0700 Subject: [PATCH 18/48] process: fix incorrect usage of assert.fail() The message argument for `assert.fail()` is the third argument, not the first. Correct minor misuse in internal module. PR-URL: https://github.com/nodejs/node/pull/6211 Reviewed-By: Brian White Reviewed-By: Ben Noordhuis Reviewed-By: James M Snell Reviewed-By: Evan Lucas Reviewed-By: Colin Ihrig --- lib/internal/process/promises.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/process/promises.js b/lib/internal/process/promises.js index 165bf3319ee..22f1959784b 100644 --- a/lib/internal/process/promises.js +++ b/lib/internal/process/promises.js @@ -13,7 +13,7 @@ function setupPromises(scheduleMicrotasks) { else if (event === promiseRejectEvent.handled) rejectionHandled(promise); else - require('assert').fail('unexpected PromiseRejectEvent'); + require('assert').fail(null, null, 'unexpected PromiseRejectEvent'); }); function unhandledRejection(promise, reason) { From af4a380d400129560844eecc3bbd1208af19dfe7 Mon Sep 17 00:00:00 2001 From: Michael Dawson Date: Thu, 14 Apr 2016 18:34:00 -0400 Subject: [PATCH 19/48] deps: cherry-pick 1ef7487b from v8 upstream Original commit message: Improved diagnostic message for JS heap out of memory This patch replaces the unused 'take_snapshot' parameter on FatalProcessOutOfMemory() with a 'is_heap_oom' parameter. The parameter is set to true on error paths where the JS heap is out of memory, as distinct from a malloc() failure i.e. process out of memory. The message output to stderr or passed to embedding applications via FatalErrorCallback is 'Javascript heap out of memory' rather than 'process out of memory'. BUG= R=jochen@chromium.org, verwaest@chromium.org, michael_dawson@ca.ibm.com Review URL: https://codereview.chromium.org/1873443002 Cr-Commit-Position: refs/heads/master@{#35431} We'd like this in 6.x to help with diagnosing customer problems. It provides a better message on OOM so that it is easier to be able to tell whether the OOM was due to heap exhaustion or running out of native memory. PR-URL: https://github.com/nodejs/node/pull/6218 Reviewed-By: Ben Noordhuis Reviewed-By: James M Snell --- deps/v8/src/api.cc | 6 ++++-- deps/v8/src/heap/heap.cc | 8 +++----- deps/v8/src/heap/heap.h | 2 +- deps/v8/src/heap/mark-compact.cc | 4 ++-- deps/v8/src/v8.h | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index a71dcfaec31..0247d950a74 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -226,7 +226,7 @@ void i::FatalProcessOutOfMemory(const char* location) { // When V8 cannot allocated memory FatalProcessOutOfMemory is called. // The default fatal error handler is called and execution is stopped. -void i::V8::FatalProcessOutOfMemory(const char* location, bool take_snapshot) { +void i::V8::FatalProcessOutOfMemory(const char* location, bool is_heap_oom) { i::Isolate* isolate = i::Isolate::Current(); char last_few_messages[Heap::kTraceRingBufferSize + 1]; char js_stacktrace[Heap::kStacktraceBufferSize + 1]; @@ -288,7 +288,9 @@ void i::V8::FatalProcessOutOfMemory(const char* location, bool take_snapshot) { PrintF("\n<--- Last few GCs --->\n%s\n", first_newline); PrintF("\n<--- JS stacktrace --->\n%s\n", js_stacktrace); } - Utils::ApiCheck(false, location, "Allocation failed - process out of memory"); + Utils::ApiCheck(false, location, is_heap_oom + ? "Allocation failed - JavaScript heap out of memory" + : "Allocation failed - process out of memory"); // If the fatal error handler returns, we stop execution. FATAL("API fatal error handler returned after process out of memory"); } diff --git a/deps/v8/src/heap/heap.cc b/deps/v8/src/heap/heap.cc index ad6c451cbe8..dad6ca6ebf2 100644 --- a/deps/v8/src/heap/heap.cc +++ b/deps/v8/src/heap/heap.cc @@ -3969,8 +3969,7 @@ AllocationResult Heap::AllocateUninitializedFixedDoubleArray( AllocationResult Heap::AllocateRawFixedDoubleArray(int length, PretenureFlag pretenure) { if (length < 0 || length > FixedDoubleArray::kMaxLength) { - v8::internal::Heap::FatalProcessOutOfMemory("invalid array length", - kDoubleAligned); + v8::internal::Heap::FatalProcessOutOfMemory("invalid array length", true); } int size = FixedDoubleArray::SizeFor(length); AllocationSpace space = SelectSpace(pretenure); @@ -5501,9 +5500,8 @@ void Heap::CompactRetainedMaps(ArrayList* retained_maps) { if (new_length != length) retained_maps->SetLength(new_length); } - -void Heap::FatalProcessOutOfMemory(const char* location, bool take_snapshot) { - v8::internal::V8::FatalProcessOutOfMemory(location, take_snapshot); +void Heap::FatalProcessOutOfMemory(const char* location, bool is_heap_oom) { + v8::internal::V8::FatalProcessOutOfMemory(location, is_heap_oom); } #ifdef DEBUG diff --git a/deps/v8/src/heap/heap.h b/deps/v8/src/heap/heap.h index 4a76777ecd0..f8467ba8f9a 100644 --- a/deps/v8/src/heap/heap.h +++ b/deps/v8/src/heap/heap.h @@ -552,7 +552,7 @@ class Heap { static inline bool IsOneByte(T t, int chars); static void FatalProcessOutOfMemory(const char* location, - bool take_snapshot = false); + bool is_heap_oom = false); static bool RootIsImmortalImmovable(int root_index); diff --git a/deps/v8/src/heap/mark-compact.cc b/deps/v8/src/heap/mark-compact.cc index 646e63402a6..641ac7d1dc9 100644 --- a/deps/v8/src/heap/mark-compact.cc +++ b/deps/v8/src/heap/mark-compact.cc @@ -1675,8 +1675,8 @@ class MarkCompactCollector::EvacuateNewSpaceVisitor final compaction_spaces_->Get(OLD_SPACE)->AllocateRaw(size_in_bytes, alignment); if (allocation.IsRetry()) { - FatalProcessOutOfMemory( - "MarkCompactCollector: semi-space copy, fallback in old gen\n"); + v8::internal::Heap::FatalProcessOutOfMemory( + "MarkCompactCollector: semi-space copy, fallback in old gen", true); } return allocation; } diff --git a/deps/v8/src/v8.h b/deps/v8/src/v8.h index 6016ef1419f..a1b18b20d6c 100644 --- a/deps/v8/src/v8.h +++ b/deps/v8/src/v8.h @@ -21,7 +21,7 @@ class V8 : public AllStatic { // Report process out of memory. Implementation found in api.cc. // This function will not return, but will terminate the execution. static void FatalProcessOutOfMemory(const char* location, - bool take_snapshot = false); + bool is_heap_oom = false); static void InitializePlatform(v8::Platform* platform); static void ShutdownPlatform(); From 58561cf6a8ce6ac907973c3813cb52134ec8d4c2 Mon Sep 17 00:00:00 2001 From: Brian White Date: Fri, 15 Apr 2016 01:25:21 -0400 Subject: [PATCH 20/48] tools: move message listener to worker objects Moving the `message` event listener from the cluster object to each worker object allows easier backporting of the recent jslint changes since v5.x and older do not have v6.x's `worker` parameter in the cluster object's `message` event. PR-URL: https://github.com/nodejs/node/pull/6212 Reviewed-By: Ben Noordhuis Reviewed-By: James M Snell Reviewed-By: Jeremiah Senkpiel --- tools/jslint.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tools/jslint.js b/tools/jslint.js index 7cd2fd7bcb6..754ac1a98ca 100644 --- a/tools/jslint.js +++ b/tools/jslint.js @@ -125,20 +125,6 @@ if (cluster.isMaster) { sendWork(worker); }); - cluster.on('message', function(worker, results) { - if (typeof results !== 'number') { - // The worker sent us results that are not all successes - if (!workerConfig.sendAll) - failures += results.length; - outFn(formatter(results) + '\r\n'); - printProgress(); - } else { - successes += results; - } - // Try to give the worker more work to do - sendWork(worker); - }); - process.on('exit', function() { if (showProgress) { curPath = 'Done'; @@ -149,7 +135,21 @@ if (cluster.isMaster) { }); for (i = 0; i < numCPUs; ++i) - cluster.fork(); + cluster.fork().on('message', onWorkerMessage); + + function onWorkerMessage(results) { + if (typeof results !== 'number') { + // The worker sent us results that are not all successes + if (!workerConfig.sendAll) + failures += results.length; + outFn(formatter(results) + '\r\n'); + printProgress(); + } else { + successes += results; + } + // Try to give the worker more work to do + sendWork(this); + } function sendWork(worker) { if (!files || !files.length) { From 5c14d695d2c1f924cf06af6ae896027569993a5c Mon Sep 17 00:00:00 2001 From: Bryan English Date: Tue, 12 Apr 2016 11:10:49 -0700 Subject: [PATCH 21/48] doc: native module reloading is not supported Clarify in docs for require.cache that reloading native modules isn't supported. Related: #6160 PR-URL: https://github.com/nodejs/node/pull/6168 Reviewed-By: Benjamin Gruenbaum Reviewed-By: Brian White Reviewed-By: James M Snell --- doc/api/globals.markdown | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/api/globals.markdown b/doc/api/globals.markdown index 1e2e0562bd8..a43d28eccb9 100644 --- a/doc/api/globals.markdown +++ b/doc/api/globals.markdown @@ -145,7 +145,9 @@ global but rather local to each module. * {Object} Modules are cached in this object when they are required. By deleting a key -value from this object, the next `require` will reload the module. +value from this object, the next `require` will reload the module. Note that +this does not apply to [native addons][], for which reloading will result in an +Error. ### require.extensions @@ -199,6 +201,7 @@ but rather than loading the module, just return the resolved filename. [buffer section]: buffer.html [module system documentation]: modules.html [Modules]: modules.html#modules_modules +[native addons]: addons.html [timers]: timers.html [`clearImmediate`]: timers.html#timers_clearimmediate_immediateobject [`clearInterval`]: timers.html#timers_clearinterval_intervalobject From 15d970d65c8da7970e6bacb9feccb4b830376881 Mon Sep 17 00:00:00 2001 From: Jeremiah Senkpiel Date: Thu, 14 Apr 2016 10:56:48 -0400 Subject: [PATCH 22/48] test,repl: use deepStrictEqual for false-y values PR-URL: https://github.com/nodejs/node/pull/6196 Reviewed-By: Colin Ihrig Reviewed-By: Rich Trott Reviewed-By: James M Snell Reviewed-By: Minwoo Jung --- test/parallel/test-repl-tab-complete.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-repl-tab-complete.js b/test/parallel/test-repl-tab-complete.js index d52f0068ec3..8f58c03664a 100644 --- a/test/parallel/test-repl-tab-complete.js +++ b/test/parallel/test-repl-tab-complete.js @@ -176,7 +176,7 @@ var spaceTimeout = setTimeout(function() { }, 1000); testMe.complete(' ', common.mustCall(function(error, data) { - assert.deepEqual(data, [[], undefined]); + assert.deepStrictEqual(data, [[], undefined]); clearTimeout(spaceTimeout); })); @@ -255,5 +255,5 @@ putIn.run(['.clear']); putIn.run(['function a() {}']); testMe.complete('a().b.', common.mustCall((error, data) => { - assert.deepEqual(data, [[], undefined]); + assert.deepStrictEqual(data, [[], undefined]); })); From 39d905e2937ab10040f45b0ab0707f8bd9bf86b9 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 15 Apr 2016 02:03:12 +0200 Subject: [PATCH 23/48] node: make builtin libs available for `--eval` Make the builtin libraries available for the `--eval` and `--print` CLI options, using the same mechanism that the REPL uses. This renders workarounds like `node -e 'require("fs").doStuff()'` unnecessary. As part of this, the list of builtin modules and the code for adding the corresponding properties to the target context is moved to `internal/module.js`, and the previously missing `repl` entry is added. PR-URL: https://github.com/nodejs/node/pull/6207 Reviewed-By: James M Snell Reviewed-By: Colin Ihrig --- doc/api/cli.markdown | 3 ++- lib/internal/bootstrap_node.js | 3 +++ lib/internal/module.js | 35 +++++++++++++++++++++++++++++++++- lib/repl.js | 23 ++-------------------- test/parallel/test-cli-eval.js | 7 +++++++ 5 files changed, 48 insertions(+), 23 deletions(-) diff --git a/doc/api/cli.markdown b/doc/api/cli.markdown index 52e3f2709c3..e03773d1e71 100644 --- a/doc/api/cli.markdown +++ b/doc/api/cli.markdown @@ -36,7 +36,8 @@ The output of this option is less detailed than this document. ### `-e`, `--eval "script"` -Evaluate the following argument as JavaScript. +Evaluate the following argument as JavaScript. The modules which are +predefined in the REPL can also be used in `script`. ### `-p`, `--print "script"` diff --git a/lib/internal/bootstrap_node.js b/lib/internal/bootstrap_node.js index 2960234fa08..195dfbc0fb8 100644 --- a/lib/internal/bootstrap_node.js +++ b/lib/internal/bootstrap_node.js @@ -105,6 +105,9 @@ // User passed '-e' or '--eval' arguments to Node without '-i' or // '--interactive' preloadModules(); + + const internalModule = NativeModule.require('internal/module'); + internalModule.addBuiltinLibsToObject(global); evalScript('[eval]'); } else if (process.argv[1]) { // make process.argv[1] into a full path diff --git a/lib/internal/module.js b/lib/internal/module.js index 9918c736266..aa1ffc01428 100644 --- a/lib/internal/module.js +++ b/lib/internal/module.js @@ -1,6 +1,10 @@ 'use strict'; -exports = module.exports = { makeRequireFunction, stripBOM }; +exports = module.exports = { + makeRequireFunction, + stripBOM, + addBuiltinLibsToObject +}; exports.requireDepth = 0; @@ -46,3 +50,32 @@ function stripBOM(content) { } return content; } + +exports.builtinLibs = ['assert', 'buffer', 'child_process', 'cluster', + 'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'https', 'net', + 'os', 'path', 'punycode', 'querystring', 'readline', 'repl', 'stream', + 'string_decoder', 'tls', 'tty', 'url', 'util', 'v8', 'vm', 'zlib']; + +function addBuiltinLibsToObject(object) { + // Make built-in modules available directly (loaded lazily). + exports.builtinLibs.forEach((name) => { + Object.defineProperty(object, name, { + get: () => { + const lib = require(name); + // This implicitly invokes the setter, so that this getter is only + // invoked at most once and does not overwrite anything. + object[name] = lib; + return lib; + }, + // Allow the creation of other globals with this name. + set: (val) => { + // Deleting the property before re-assigning it disables the + // getter/setter mechanism. + delete object[name]; + object[name] = val; + }, + configurable: true, + enumerable: false + }); + }); +} diff --git a/lib/repl.js b/lib/repl.js index 82555497ebf..d802ff304c0 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -64,10 +64,7 @@ function hasOwnProperty(obj, prop) { // This is the default "writer" value if none is passed in the REPL options. exports.writer = util.inspect; -exports._builtinLibs = ['assert', 'buffer', 'child_process', 'cluster', - 'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'https', 'net', - 'os', 'path', 'punycode', 'querystring', 'readline', 'stream', - 'string_decoder', 'tls', 'tty', 'url', 'util', 'v8', 'vm', 'zlib']; +exports._builtinLibs = internalModule.builtinLibs; const BLOCK_SCOPED_ERROR = 'Block-scoped declarations (let, ' + @@ -565,23 +562,7 @@ REPLServer.prototype.createContext = function() { this.lines = []; this.lines.level = []; - // make built-in modules available directly - // (loaded lazily) - exports._builtinLibs.forEach((name) => { - Object.defineProperty(context, name, { - get: () => { - var lib = require(name); - this.last = context[name] = lib; - return lib; - }, - // allow the creation of other globals with this name - set: (val) => { - delete context[name]; - context[name] = val; - }, - configurable: true - }); - }); + internalModule.addBuiltinLibsToObject(context); Object.defineProperty(context, '_', { configurable: true, diff --git a/test/parallel/test-cli-eval.js b/test/parallel/test-cli-eval.js index d1db3a815f5..a58c023eb6d 100644 --- a/test/parallel/test-cli-eval.js +++ b/test/parallel/test-cli-eval.js @@ -53,6 +53,13 @@ child.exec(nodejs + ' --eval "require(\'' + filename + '\')"', assert.equal(status.code, 42); }); +// Check that builtin modules are pre-defined. +child.exec(nodejs + ' --print "os.platform()"', + function(status, stdout, stderr) { + assert.strictEqual(stderr, ''); + assert.strictEqual(stdout.trim(), require('os').platform()); + }); + // module path resolve bug, regression test child.exec(nodejs + ' --eval "require(\'./test/parallel/test-cli-eval.js\')"', function(status, stdout, stderr) { From ebc8c37f70a84a64851b440493f3441eb9f70fdb Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Mon, 18 Apr 2016 13:19:12 +0200 Subject: [PATCH 24/48] repl: keep the built-in modules non-enumerable Make sure that the built-in modules in the repl stay non-enumerable. Previously, they would pop up as enumerable properties of the global object after having been accessed for the first time. PR-URL: https://github.com/nodejs/node/pull/6207 Reviewed-By: James M Snell Reviewed-By: Colin Ihrig --- lib/internal/module.js | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/lib/internal/module.js b/lib/internal/module.js index aa1ffc01428..a12af12f3e3 100644 --- a/lib/internal/module.js +++ b/lib/internal/module.js @@ -59,21 +59,36 @@ exports.builtinLibs = ['assert', 'buffer', 'child_process', 'cluster', function addBuiltinLibsToObject(object) { // Make built-in modules available directly (loaded lazily). exports.builtinLibs.forEach((name) => { + // Goals of this mechanism are: + // - Lazy loading of built-in modules + // - Having all built-in modules available as non-enumerable properties + // - Allowing the user to re-assign these variables as if there were no + // pre-existing globals with the same name. + + const setReal = (val) => { + // Deleting the property before re-assigning it disables the + // getter/setter mechanism. + delete object[name]; + object[name] = val; + }; + Object.defineProperty(object, name, { get: () => { const lib = require(name); - // This implicitly invokes the setter, so that this getter is only - // invoked at most once and does not overwrite anything. - object[name] = lib; - return lib; - }, - // Allow the creation of other globals with this name. - set: (val) => { - // Deleting the property before re-assigning it disables the - // getter/setter mechanism. + + // Disable the current getter/setter and set up a new + // non-enumerable property. delete object[name]; - object[name] = val; + Object.defineProperty(object, name, { + get: () => lib, + set: setReal, + configurable: true, + enumerable: false + }); + + return lib; }, + set: setReal, configurable: true, enumerable: false }); From 40a57619690beb8808b04746f9c2922108d8542a Mon Sep 17 00:00:00 2001 From: James M Snell Date: Tue, 12 Apr 2016 11:27:29 -0700 Subject: [PATCH 25/48] doc: explain differences in console.assert between node and browsers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide an example for implementing browser like behavior for console.assert. This "fixes" https://github.com/nodejs/node/issues/5340 by providing an alternative to changing Node.js' implemented behavior. Instead, we document the differences and show how to work around them if browser like semantics are desired. Fixes: https://github.com/nodejs/node/issues/5340 PR-URL: https://github.com/nodejs/node/pull/6169 Reviewed-By: Robert Jefe Lindstädt Reviewed-By: Jeff Harris <@techjeffharris> --- doc/api/console.markdown | 41 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/doc/api/console.markdown b/doc/api/console.markdown index 6cf5051af25..32dab8e7171 100644 --- a/doc/api/console.markdown +++ b/doc/api/console.markdown @@ -109,6 +109,46 @@ console.assert(false, 'Whoops %s', 'didn\'t work'); // AssertionError: Whoops didn't work ``` +*Note: the `console.assert()` method is implemented differently in Node.js +than the `console.assert()` method [available in browsers][web-api-assert].* + +Specifically, in browsers, calling `console.assert()` with a falsy +assertion will cause the `message` to be printed to the console without +interrupting execution of subsequent code. In Node.js, however, a falsy +assertion will cause an `AssertionError` to be thrown. + +Functionality approximating that implemented by browsers can be implemented +by extending Node.js' `console` and overriding the `console.assert()` method. + +In the following example, a simple module is created that extends and overrides +the default behavior of `console` in Node.js. + +```js +'use strict'; + +// Creates a simple extension of console with a +// new impl for assert without monkey-patching. +const myConsole = Object.setPrototypeOf({ + assert(assertion, message, ...args) { + try { + console.assert(assertion, message, ...args); + } catch (err) { + console.error(err.stack); + } + } +}, console); + +module.exports = myConsole; +``` + +This can then be used as a direct replacement for the built in console: + +```js +const console = require('./myConsole'); +console.assert(false, 'this message will print, but no error thrown'); +console.log('this will also print'); +``` + ### console.dir(obj[, options]) Uses [`util.inspect()`][] on `obj` and prints the resulting string to `stdout`. @@ -224,3 +264,4 @@ The `console.warn()` function is an alias for [`console.error()`][]. [`util.format()`]: util.html#util_util_format_format [`util.inspect()`]: util.html#util_util_inspect_object_options [customizing `util.inspect()` colors]: util.html#util_customizing_util_inspect_colors +[web-api-assert]: https://developer.mozilla.org/en-US/docs/Web/API/console/assert From 3641ca9849b9473d347f6aea53ba61acad2d694b Mon Sep 17 00:00:00 2001 From: Alexander Gromnitsky Date: Wed, 13 Apr 2016 13:30:14 +0300 Subject: [PATCH 26/48] doc: fix broken references PR-URL: https://github.com/nodejs/node/pull/6100 Reviewed-By: James M Snell --- doc/api/addons.markdown | 2 +- doc/api/buffer.markdown | 6 +++--- doc/api/child_process.markdown | 6 +++--- doc/api/cluster.markdown | 2 +- doc/api/crypto.markdown | 6 +++--- doc/api/domain.markdown | 2 +- doc/api/errors.markdown | 4 ++-- doc/api/http.markdown | 8 ++++---- doc/api/net.markdown | 2 +- doc/api/process.markdown | 6 +++--- doc/api/tls.markdown | 6 +++--- doc/api/vm.markdown | 2 +- 12 files changed, 26 insertions(+), 26 deletions(-) diff --git a/doc/api/addons.markdown b/doc/api/addons.markdown index c330217beff..4668bc546f2 100644 --- a/doc/api/addons.markdown +++ b/doc/api/addons.markdown @@ -1084,7 +1084,7 @@ const addon = require('./build/Release/addon'); [examples]: https://github.com/nodejs/nan/tree/master/examples/ [installation instructions]: https://github.com/nodejs/node-gyp#installation [libuv]: https://github.com/libuv/libuv -[Linking to Node.js' own dependencies]: #linking-to-nodejs-own-dependencies +[Linking to Node.js' own dependencies]: #addons_linking_to_node_js_own_dependencies [Native Abstractions for Node.js]: https://github.com/nodejs/nan [node-gyp]: https://github.com/nodejs/node-gyp [require]: globals.html#globals_require diff --git a/doc/api/buffer.markdown b/doc/api/buffer.markdown index 7153cb4ac6b..ecf9f792b3b 100644 --- a/doc/api/buffer.markdown +++ b/doc/api/buffer.markdown @@ -1845,11 +1845,11 @@ console.log(buf); [`Array#indexOf()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf [`Array#includes()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes [`buf.entries()`]: #buffer_buf_entries -[`buf.fill(0)`]: #buffer_buf_fill_value_offset_end +[`buf.fill(0)`]: #buffer_buf_fill_value_offset_end_encoding [`buf.keys()`]: #buffer_buf_keys [`buf.slice()`]: #buffer_buf_slice_start_end [`buf.values()`]: #buffer_buf_values -[`buf1.compare(buf2)`]: #buffer_buf_compare_otherbuffer +[`buf1.compare(buf2)`]: #buffer_buf_compare_target_targetstart_targetend_sourcestart_sourceend [`JSON.stringify()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify [`RangeError`]: errors.html#errors_class_rangeerror [`String.prototype.length`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length @@ -1857,7 +1857,7 @@ console.log(buf); [RFC 4648, Section 5]: https://tools.ietf.org/html/rfc4648#section-5 [buffer_from_array]: #buffer_class_method_buffer_from_array [buffer_from_buffer]: #buffer_class_method_buffer_from_buffer -[buffer_from_arraybuf]: #buffer_class_method_buffer_from_arraybuffer +[buffer_from_arraybuf]: #buffer_class_method_buffer_from_arraybuffer_byteoffset_length [buffer_from_string]: #buffer_class_method_buffer_from_str_encoding [buffer_allocunsafe]: #buffer_class_method_buffer_allocunsafe_size [buffer_allocunsafeslow]: #buffer_class_method_buffer_allocunsafeslow_size diff --git a/doc/api/child_process.markdown b/doc/api/child_process.markdown index 31ebf4fbb9e..2c8665be58f 100644 --- a/doc/api/child_process.markdown +++ b/doc/api/child_process.markdown @@ -1058,10 +1058,10 @@ console.log('中文测试'); [`child_process.spawn()`]: #child_process_child_process_spawn_command_args_options [`child_process.spawnSync()`]: #child_process_child_process_spawnsync_command_args_options [`ChildProcess#kill()`]: #child_process_child_kill_signal -[`ChildProcess#send()`]: #child_process_child_send_message_sendhandle_callback +[`ChildProcess#send()`]: #child_process_child_send_message_sendhandle_options_callback [`Error`]: errors.html#errors_class_error -[`EventEmitter`]: events.html#events_class_events_eventemitter -[`EventEmitters`]: events.html#events_class_events_eventemitter +[`EventEmitter`]: events.html#events_class_eventemitter +[`EventEmitters`]: events.html#events_class_eventemitter [`net.Server`]: net.html#net_class_net_server [`net.Socket`]: net.html#net_class_net_socket [`options.detached`]: #child_process_options_detached diff --git a/doc/api/cluster.markdown b/doc/api/cluster.markdown index f510468c898..8937aa91287 100644 --- a/doc/api/cluster.markdown +++ b/doc/api/cluster.markdown @@ -703,7 +703,7 @@ socket.on('data', (id) => { ``` [`child_process.fork()`]: child_process.html#child_process_child_process_fork_modulepath_args_options -[`ChildProcess.send()`]: child_process.html#child_process_child_send_message_sendhandle_callback +[`ChildProcess.send()`]: child_process.html#child_process_child_send_message_sendhandle_options_callback [`disconnect`]: child_process.html#child_process_child_disconnect [`kill`]: process.html#process_process_kill_pid_signal [`server.close()`]: net.html#net_event_close diff --git a/doc/api/crypto.markdown b/doc/api/crypto.markdown index 6ec19ea41d2..14adffd8d8e 100644 --- a/doc/api/crypto.markdown +++ b/doc/api/crypto.markdown @@ -1405,11 +1405,11 @@ See the reference for other recommendations and details. [`hash.digest()`]: #crypto_hash_digest_encoding [`hash.update()`]: #crypto_hash_update_data_input_encoding [`hmac.digest()`]: #crypto_hmac_digest_encoding -[`hmac.update()`]: #crypto_hmac_update_data +[`hmac.update()`]: #crypto_hmac_update_data_input_encoding [`sign.sign()`]: #crypto_sign_sign_private_key_output_format -[`sign.update()`]: #crypto_sign_update_data +[`sign.update()`]: #crypto_sign_update_data_input_encoding [`tls.createSecureContext()`]: tls.html#tls_tls_createsecurecontext_details -[`verify.update()`]: #crypto_verifier_update_data +[`verify.update()`]: #crypto_verifier_update_data_input_encoding [`verify.verify()`]: #crypto_verifier_verify_object_signature_signature_format [Caveats]: #crypto_support_for_weak_or_compromised_algorithms [HTML5's `keygen` element]: http://www.w3.org/TR/html5/forms.html#the-keygen-element diff --git a/doc/api/domain.markdown b/doc/api/domain.markdown index 41d27c5625f..c556e2533c0 100644 --- a/doc/api/domain.markdown +++ b/doc/api/domain.markdown @@ -448,7 +448,7 @@ is emitted. [`domain.dispose()`]: #domain_domain_dispose [`domain.exit()`]: #domain_domain_exit [`Error`]: errors.html#errors_class_error -[`EventEmitter`]: events.html#events_class_events_eventemitter +[`EventEmitter`]: events.html#events_class_eventemitter [`setInterval()`]: timers.html#timers_setinterval_callback_delay_arg [`setTimeout()`]: timers.html#timers_settimeout_callback_delay_arg [`throw`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw diff --git a/doc/api/errors.markdown b/doc/api/errors.markdown index 2d4ba89e00a..0dfe520e35c 100644 --- a/doc/api/errors.markdown +++ b/doc/api/errors.markdown @@ -520,7 +520,7 @@ found [here][online]. encountered by [`http`][] or [`net`][] -- often a sign that a `socket.end()` was not properly called. -[`fs.readdir`]: fs.html#fs_fs_readdir_path_callback +[`fs.readdir`]: fs.html#fs_fs_readdir_path_options_callback [`fs.readFileSync`]: fs.html#fs_fs_readfilesync_file_options [`fs.unlink`]: fs.html#fs_fs_unlink_path_callback [`fs`]: fs.html @@ -529,7 +529,7 @@ found [here][online]. [`net`]: net.html [`process.on('uncaughtException')`]: process.html#process_event_uncaughtexception [domains]: domain.html -[event emitter-based]: events.html#events_class_events_eventemitter +[event emitter-based]: events.html#events_class_eventemitter [file descriptors]: https://en.wikipedia.org/wiki/File_descriptor [online]: http://man7.org/linux/man-pages/man3/errno.3.html [stream-based]: stream.html diff --git a/doc/api/http.markdown b/doc/api/http.markdown index b2fc5dbba00..124bd029fd5 100644 --- a/doc/api/http.markdown +++ b/doc/api/http.markdown @@ -1225,10 +1225,10 @@ There are a few special headers that should be noted. [`'listening'`]: net.html#net_event_listening [`'response'`]: #http_event_response [`Agent`]: #http_class_http_agent -[`agent.createConnection()`]: #http_agent_createconnection +[`agent.createConnection()`]: #http_agent_createconnection_options_callback [`Buffer`]: buffer.html#buffer_buffer [`destroy()`]: #http_agent_destroy -[`EventEmitter`]: events.html#events_class_events_eventemitter +[`EventEmitter`]: events.html#events_class_eventemitter [`http.Agent`]: #http_class_http_agent [`http.ClientRequest`]: #http_class_http_clientrequest [`http.globalAgent`]: #http_http_globalagent @@ -1240,8 +1240,8 @@ There are a few special headers that should be noted. [`net.createConnection()`]: net.html#net_net_createconnection_options_connectlistener [`net.Server`]: net.html#net_class_net_server [`net.Server.close()`]: net.html#net_server_close_callback -[`net.Server.listen()`]: net.html#net_server_listen_handle_callback -[`net.Server.listen(path)`]: net.html#net_server_listen_path_callback +[`net.Server.listen()`]: net.html#net_server_listen_handle_backlog_callback +[`net.Server.listen(path)`]: net.html#net_server_listen_path_backlog_callback [`net.Server.listen(port)`]: net.html#net_server_listen_port_hostname_backlog_callback [`net.Socket`]: net.html#net_class_net_socket [`request.socket.getPeerCertificate()`]: tls.html#tls_tlssocket_getpeercertificate_detailed diff --git a/doc/api/net.markdown b/doc/api/net.markdown index 10129c13b89..7a58bf23108 100644 --- a/doc/api/net.markdown +++ b/doc/api/net.markdown @@ -724,7 +724,7 @@ Returns true if input is a version 6 IP address, otherwise returns false. [`dns.lookup()`]: dns.html#dns_dns_lookup_hostname_options_callback [`dns.lookup()` hints]: #dns_supported_getaddrinfo_flags [`end()`]: #net_socket_end_data_encoding -[`EventEmitter`]: events.html#events_class_events_eventemitter +[`EventEmitter`]: events.html#events_class_eventemitter [`net.Socket`]: #net_class_net_socket [`pause()`]: #net_socket_pause [`resume()`]: #net_socket_resume diff --git a/doc/api/process.markdown b/doc/api/process.markdown index 2e65e6a4b1e..841984a1e9f 100644 --- a/doc/api/process.markdown +++ b/doc/api/process.markdown @@ -1285,9 +1285,9 @@ Will print something like: [`'message'`]: child_process.html#child_process_event_message [`ChildProcess.disconnect()`]: child_process.html#child_process_child_disconnect -[`ChildProcess.send()`]: child_process.html#child_process_child_send_message_sendhandle_callback +[`ChildProcess.send()`]: child_process.html#child_process_child_send_message_sendhandle_options_callback [`Error`]: errors.html#errors_class_error -[`EventEmitter`]: events.html#events_class_events_eventemitter +[`EventEmitter`]: events.html#events_class_eventemitter [`net.Server`]: net.html#net_class_net_server [`net.Socket`]: net.html#net_class_net_socket [`process.exit()`]: #process_process_exit_code @@ -1300,4 +1300,4 @@ Will print something like: [the tty docs]: tty.html#tty_tty [`JSON.stringify()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify [process_warning]: #process_event_warning -[process_emit_warning]: #process_emitwarning_warning_name_ctor +[process_emit_warning]: #process_process_emitwarning_warning_name_ctor diff --git a/doc/api/tls.markdown b/doc/api/tls.markdown index ef1c7fc32bd..ae324f8852e 100644 --- a/doc/api/tls.markdown +++ b/doc/api/tls.markdown @@ -175,7 +175,7 @@ Returned by tls.createSecurePair. This event is emitted from the SecurePair once the pair has successfully established a secure connection. -As with checking for the server [`secureConnection`](#event-secureconnection) +As with checking for the server [`secureConnection`](#tls_event_secureconnection) event, `pair.cleartext.authorized` should be inspected to confirm whether the certificate used is properly authorized. @@ -339,7 +339,7 @@ See `net.Server` for more information. Updates the keys for encryption/decryption of the [TLS Session Tickets][]. NOTE: the buffer should be 48 bytes long. See `ticketKeys` option in -[tls.createServer](#tlscreateserveroptions-secureconnectionlistener) for +[tls.createServer](#tls_tls_createserver_options_secureconnectionlistener) for more information on how it is used. NOTE: the change is effective only for future server connections. Existing @@ -1004,5 +1004,5 @@ console.log(ciphers); // ['AES128-SHA', 'AES256-SHA', ...] [TLS recommendations]: https://wiki.mozilla.org/Security/Server_Side_TLS [TLS Session Tickets]: https://www.ietf.org/rfc/rfc5077.txt [`tls.TLSSocket.getPeerCertificate()`]: #tls_tlssocket_getpeercertificate_detailed -[`tls.createSecureContext()`]: #tls_tls_createsecurecontext_details +[`tls.createSecureContext()`]: #tls_tls_createsecurecontext_options [`tls.connect()`]: #tls_tls_connect_options_callback diff --git a/doc/api/vm.markdown b/doc/api/vm.markdown index 28d760a798e..a9b5463b3f2 100644 --- a/doc/api/vm.markdown +++ b/doc/api/vm.markdown @@ -124,7 +124,7 @@ requires a separate process. ### script.runInThisContext([options]) -Similar to [`vm.runInThisContext()`]() but a method of a precompiled `Script` +Similar to [`vm.runInThisContext()`][] but a method of a precompiled `Script` object. `script.runInThisContext()` runs `script`'s compiled code and returns the result. Running code does not have access to local scope, but does have access to the current `global` object. From 64d36bec23766f4d797fb945c5311780c5a709f0 Mon Sep 17 00:00:00 2001 From: Mike Kaufman Date: Tue, 5 Apr 2016 16:15:55 -0700 Subject: [PATCH 27/48] gitignore: ignore VS 2015 *.VC.opendb files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These files are created by VS 2015 and should be ignored by git. PR-URL: https://github.com/nodejs/node/pull/6070 Reviewed-By: Johan Bergström Reviewed-By: Rich Trott Reviewed-By: James M Snell --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 734d92d4d71..db08050e14e 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,7 @@ _UpgradeReport_Files/ ipch/ *.sdf *.opensdf +*.VC.opendb /config.mk /config.gypi From 61886fad735d3c77372e6581107a4b549f361034 Mon Sep 17 00:00:00 2001 From: Mike Kaufman Date: Wed, 13 Apr 2016 14:38:19 -0700 Subject: [PATCH 28/48] gitignore: adding .vs/ directory to .gitignore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is created by vs 2015 for user & machine-specific files and should be ignored by git. PR-URL: https://github.com/nodejs/node/pull/6070 Reviewed-By: Johan Bergström Reviewed-By: Rich Trott Reviewed-By: James M Snell --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index db08050e14e..c7361af80c7 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ ipch/ *.sdf *.opensdf *.VC.opendb +.vs/ /config.mk /config.gypi From 7097212cb619457e06036eac84e529899c3fd0f9 Mon Sep 17 00:00:00 2001 From: "Steven R. Loomis" Date: Tue, 5 Apr 2016 15:19:35 -0700 Subject: [PATCH 29/48] tools: fix license-builder.sh again for ICU * Modify tools/license-builder.sh to support ICU 57.1's plain text license. (Separate issue to add ICU 57.1 in #6058) * Update/regenerate LICENSE to include ICU 57.1's license * Note that because the tool was rerun, the change in #6065 is already included here. PR-URL: https://github.com/nodejs/node/pull/6068 Reviewed-By: Rod Vagg Reviewed-By: James M Snell --- LICENSE | 536 +++++++++++++++++++++------------------ tools/license-builder.sh | 20 +- 2 files changed, 303 insertions(+), 253 deletions(-) diff --git a/LICENSE b/LICENSE index 5f436ffb3d2..d0d07f7d429 100644 --- a/LICENSE +++ b/LICENSE @@ -102,44 +102,51 @@ The externally maintained libraries used by Node.js are: COPYRIGHT AND PERMISSION NOTICE - Copyright (c) 1995-2015 International Business Machines Corporation and others + Copyright (c) 1995-2016 International Business Machines Corporation and others All rights reserved. - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, and/or sell - copies of the Software, and to permit persons + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, provided that the above - copyright notice(s) and this permission notice appear in all copies - of the Software and that both the above copyright notice(s) and this + copyright notice(s) and this permission notice appear in all copies of + the Software and that both the above copyright notice(s) and this permission notice appear in supporting documentation. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL - THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, - OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER - RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE - USE OR PERFORMANCE OF THIS SOFTWARE. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT + OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY + SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER + RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - Except as contained in this notice, the name of a copyright holder shall not be - used in advertising or otherwise to promote the sale, use or other dealings in - this Software without prior written authorization of the copyright holder. + Except as contained in this notice, the name of a copyright holder + shall not be used in advertising or otherwise to promote the sale, use + or other dealings in this Software without prior written authorization + of the copyright holder. - All trademarks and registered trademarks mentioned herein are the property of their respective owners. + All trademarks and registered trademarks mentioned herein are the + property of their respective owners. + + --------------------- Third-Party Software Licenses - This section contains third-party software notices and/or additional terms for licensed - third-party software components included within ICU libraries. + + This section contains third-party software notices and/or additional + terms for licensed third-party software components included within ICU + libraries. 1. Unicode Data Files and Software COPYRIGHT AND PERMISSION NOTICE - Copyright © 1991-2015 Unicode, Inc. All rights reserved. + Copyright © 1991-2016 Unicode, Inc. All rights reserved. Distributed under the Terms of Use in http://www.unicode.org/copyright.html. @@ -177,281 +184,312 @@ The externally maintained libraries used by Node.js are: 2. Chinese/Japanese Word Break Dictionary Data (cjdict.txt) - # The Google Chrome software developed by Google is licensed under the BSD license. Other software included in this distribution is provided under other licenses, as set forth below. + # The Google Chrome software developed by Google is licensed under + # the BSD license. Other software included in this distribution is + # provided under other licenses, as set forth below. # - # The BSD License - # http://opensource.org/licenses/bsd-license.php - # Copyright (C) 2006-2008, Google Inc. + # The BSD License + # http://opensource.org/licenses/bsd-license.php + # Copyright (C) 2006-2008, Google Inc. # - # All rights reserved. + # All rights reserved. # - # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions are met: # - # Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - # Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - # Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + # Redistributions of source code must retain the above copyright notice, + # this list of conditions and the following disclaimer. + # Redistributions in binary form must reproduce the above + # copyright notice, this list of conditions and the following + # disclaimer in the documentation and/or other materials provided with + # the distribution. + # Neither the name of Google Inc. nor the names of its + # contributors may be used to endorse or promote products derived from + # this software without specific prior written permission. # # - # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # - # The word list in cjdict.txt are generated by combining three word lists listed - # below with further processing for compound word breaking. The frequency is generated - # with an iterative training against Google web corpora. + # The word list in cjdict.txt are generated by combining three word lists + # listed below with further processing for compound word breaking. The + # frequency is generated with an iterative training against Google web + # corpora. # - # * Libtabe (Chinese) - # - https://sourceforge.net/project/?group_id=1519 - # - Its license terms and conditions are shown below. + # * Libtabe (Chinese) + # - https://sourceforge.net/project/?group_id=1519 + # - Its license terms and conditions are shown below. # - # * IPADIC (Japanese) - # - http://chasen.aist-nara.ac.jp/chasen/distribution.html - # - Its license terms and conditions are shown below. + # * IPADIC (Japanese) + # - http://chasen.aist-nara.ac.jp/chasen/distribution.html + # - Its license terms and conditions are shown below. # - # ---------COPYING.libtabe ---- BEGIN-------------------- + # ---------COPYING.libtabe ---- BEGIN-------------------- # - # /* - # * Copyrighy (c) 1999 TaBE Project. - # * Copyright (c) 1999 Pai-Hsiang Hsiao. - # * All rights reserved. - # * - # * Redistribution and use in source and binary forms, with or without - # * modification, are permitted provided that the following conditions - # * are met: - # * - # * . Redistributions of source code must retain the above copyright - # * notice, this list of conditions and the following disclaimer. - # * . Redistributions in binary form must reproduce the above copyright - # * notice, this list of conditions and the following disclaimer in - # * the documentation and/or other materials provided with the - # * distribution. - # * . Neither the name of the TaBE Project nor the names of its - # * contributors may be used to endorse or promote products derived - # * from this software without specific prior written permission. - # * - # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - # * OF THE POSSIBILITY OF SUCH DAMAGE. - # */ + # /* + # * Copyrighy (c) 1999 TaBE Project. + # * Copyright (c) 1999 Pai-Hsiang Hsiao. + # * All rights reserved. + # * + # * Redistribution and use in source and binary forms, with or without + # * modification, are permitted provided that the following conditions + # * are met: + # * + # * . Redistributions of source code must retain the above copyright + # * notice, this list of conditions and the following disclaimer. + # * . Redistributions in binary form must reproduce the above copyright + # * notice, this list of conditions and the following disclaimer in + # * the documentation and/or other materials provided with the + # * distribution. + # * . Neither the name of the TaBE Project nor the names of its + # * contributors may be used to endorse or promote products derived + # * from this software without specific prior written permission. + # * + # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # * OF THE POSSIBILITY OF SUCH DAMAGE. + # */ # - # /* - # * Copyright (c) 1999 Computer Systems and Communication Lab, - # * Institute of Information Science, Academia Sinica. - # * All rights reserved. - # * - # * Redistribution and use in source and binary forms, with or without - # * modification, are permitted provided that the following conditions - # * are met: - # * - # * . Redistributions of source code must retain the above copyright - # * notice, this list of conditions and the following disclaimer. - # * . Redistributions in binary form must reproduce the above copyright - # * notice, this list of conditions and the following disclaimer in - # * the documentation and/or other materials provided with the - # * distribution. - # * . Neither the name of the Computer Systems and Communication Lab - # * nor the names of its contributors may be used to endorse or - # * promote products derived from this software without specific - # * prior written permission. - # * - # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - # * OF THE POSSIBILITY OF SUCH DAMAGE. - # */ + # /* + # * Copyright (c) 1999 Computer Systems and Communication Lab, + # * Institute of Information Science, Academia + # * Sinica. All rights reserved. + # * + # * Redistribution and use in source and binary forms, with or without + # * modification, are permitted provided that the following conditions + # * are met: + # * + # * . Redistributions of source code must retain the above copyright + # * notice, this list of conditions and the following disclaimer. + # * . Redistributions in binary form must reproduce the above copyright + # * notice, this list of conditions and the following disclaimer in + # * the documentation and/or other materials provided with the + # * distribution. + # * . Neither the name of the Computer Systems and Communication Lab + # * nor the names of its contributors may be used to endorse or + # * promote products derived from this software without specific + # * prior written permission. + # * + # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # * OF THE POSSIBILITY OF SUCH DAMAGE. + # */ # - # Copyright 1996 Chih-Hao Tsai @ Beckman Institute, University of Illinois - # c-tsai4@uiuc.edu http://casper.beckman.uiuc.edu/~c-tsai4 + # Copyright 1996 Chih-Hao Tsai @ Beckman Institute, + # University of Illinois + # c-tsai4@uiuc.edu http://casper.beckman.uiuc.edu/~c-tsai4 # - # ---------------COPYING.libtabe-----END------------------------------------ + # ---------------COPYING.libtabe-----END-------------------------------- # # - # ---------------COPYING.ipadic-----BEGIN------------------------------------ + # ---------------COPYING.ipadic-----BEGIN------------------------------- # - # Copyright 2000, 2001, 2002, 2003 Nara Institute of Science - # and Technology. All Rights Reserved. + # Copyright 2000, 2001, 2002, 2003 Nara Institute of Science + # and Technology. All Rights Reserved. # - # Use, reproduction, and distribution of this software is permitted. - # Any copy of this software, whether in its original form or modified, - # must include both the above copyright notice and the following - # paragraphs. + # Use, reproduction, and distribution of this software is permitted. + # Any copy of this software, whether in its original form or modified, + # must include both the above copyright notice and the following + # paragraphs. # - # Nara Institute of Science and Technology (NAIST), - # the copyright holders, disclaims all warranties with regard to this - # software, including all implied warranties of merchantability and - # fitness, in no event shall NAIST be liable for - # any special, indirect or consequential damages or any damages - # whatsoever resulting from loss of use, data or profits, whether in an - # action of contract, negligence or other tortuous action, arising out - # of or in connection with the use or performance of this software. + # Nara Institute of Science and Technology (NAIST), + # the copyright holders, disclaims all warranties with regard to this + # software, including all implied warranties of merchantability and + # fitness, in no event shall NAIST be liable for + # any special, indirect or consequential damages or any damages + # whatsoever resulting from loss of use, data or profits, whether in an + # action of contract, negligence or other tortuous action, arising out + # of or in connection with the use or performance of this software. # - # A large portion of the dictionary entries - # originate from ICOT Free Software. The following conditions for ICOT - # Free Software applies to the current dictionary as well. + # A large portion of the dictionary entries + # originate from ICOT Free Software. The following conditions for ICOT + # Free Software applies to the current dictionary as well. # - # Each User may also freely distribute the Program, whether in its - # original form or modified, to any third party or parties, PROVIDED - # that the provisions of Section 3 ("NO WARRANTY") will ALWAYS appear - # on, or be attached to, the Program, which is distributed substantially - # in the same form as set out herein and that such intended - # distribution, if actually made, will neither violate or otherwise - # contravene any of the laws and regulations of the countries having - # jurisdiction over the User or the intended distribution itself. + # Each User may also freely distribute the Program, whether in its + # original form or modified, to any third party or parties, PROVIDED + # that the provisions of Section 3 ("NO WARRANTY") will ALWAYS appear + # on, or be attached to, the Program, which is distributed substantially + # in the same form as set out herein and that such intended + # distribution, if actually made, will neither violate or otherwise + # contravene any of the laws and regulations of the countries having + # jurisdiction over the User or the intended distribution itself. # - # NO WARRANTY + # NO WARRANTY # - # The program was produced on an experimental basis in the course of the - # research and development conducted during the project and is provided - # to users as so produced on an experimental basis. Accordingly, the - # program is provided without any warranty whatsoever, whether express, - # implied, statutory or otherwise. The term "warranty" used herein - # includes, but is not limited to, any warranty of the quality, - # performance, merchantability and fitness for a particular purpose of - # the program and the nonexistence of any infringement or violation of - # any right of any third party. + # The program was produced on an experimental basis in the course of the + # research and development conducted during the project and is provided + # to users as so produced on an experimental basis. Accordingly, the + # program is provided without any warranty whatsoever, whether express, + # implied, statutory or otherwise. The term "warranty" used herein + # includes, but is not limited to, any warranty of the quality, + # performance, merchantability and fitness for a particular purpose of + # the program and the nonexistence of any infringement or violation of + # any right of any third party. # - # Each user of the program will agree and understand, and be deemed to - # have agreed and understood, that there is no warranty whatsoever for - # the program and, accordingly, the entire risk arising from or - # otherwise connected with the program is assumed by the user. + # Each user of the program will agree and understand, and be deemed to + # have agreed and understood, that there is no warranty whatsoever for + # the program and, accordingly, the entire risk arising from or + # otherwise connected with the program is assumed by the user. # - # Therefore, neither ICOT, the copyright holder, or any other - # organization that participated in or was otherwise related to the - # development of the program and their respective officials, directors, - # officers and other employees shall be held liable for any and all - # damages, including, without limitation, general, special, incidental - # and consequential damages, arising out of or otherwise in connection - # with the use or inability to use the program or any product, material - # or result produced or otherwise obtained by using the program, - # regardless of whether they have been advised of, or otherwise had - # knowledge of, the possibility of such damages at any time during the - # project or thereafter. Each user will be deemed to have agreed to the - # foregoing by his or her commencement of use of the program. The term - # "use" as used herein includes, but is not limited to, the use, - # modification, copying and distribution of the program and the - # production of secondary products from the program. + # Therefore, neither ICOT, the copyright holder, or any other + # organization that participated in or was otherwise related to the + # development of the program and their respective officials, directors, + # officers and other employees shall be held liable for any and all + # damages, including, without limitation, general, special, incidental + # and consequential damages, arising out of or otherwise in connection + # with the use or inability to use the program or any product, material + # or result produced or otherwise obtained by using the program, + # regardless of whether they have been advised of, or otherwise had + # knowledge of, the possibility of such damages at any time during the + # project or thereafter. Each user will be deemed to have agreed to the + # foregoing by his or her commencement of use of the program. The term + # "use" as used herein includes, but is not limited to, the use, + # modification, copying and distribution of the program and the + # production of secondary products from the program. # - # In the case where the program, whether in its original form or - # modified, was distributed or delivered to or received by a user from - # any person, organization or entity other than ICOT, unless it makes or - # grants independently of ICOT any specific warranty to the user in - # writing, such person, organization or entity, will also be exempted - # from and not be held liable to the user for any such damages as noted - # above as far as the program is concerned. + # In the case where the program, whether in its original form or + # modified, was distributed or delivered to or received by a user from + # any person, organization or entity other than ICOT, unless it makes or + # grants independently of ICOT any specific warranty to the user in + # writing, such person, organization or entity, will also be exempted + # from and not be held liable to the user for any such damages as noted + # above as far as the program is concerned. # - # ---------------COPYING.ipadic-----END------------------------------------ + # ---------------COPYING.ipadic-----END---------------------------------- 3. Lao Word Break Dictionary Data (laodict.txt) - # Copyright (c) 2013 International Business Machines Corporation - # and others. All Rights Reserved. + # Copyright (c) 2013 International Business Machines Corporation + # and others. All Rights Reserved. # - # Project: http://code.google.com/p/lao-dictionary/ + # Project: http://code.google.com/p/lao-dictionary/ # Dictionary: http://lao-dictionary.googlecode.com/git/Lao-Dictionary.txt - # License: http://lao-dictionary.googlecode.com/git/Lao-Dictionary-LICENSE.txt - # (copied below) + # License: http://lao-dictionary.googlecode.com/git/Lao-Dictionary-LICENSE.txt + # (copied below) # - # This file is derived from the above dictionary, with slight modifications. - # -------------------------------------------------------------------------------- - # Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell. - # All rights reserved. + # This file is derived from the above dictionary, with slight + # modifications. + # ---------------------------------------------------------------------- + # Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell. + # All rights reserved. # - # Redistribution and use in source and binary forms, with or without modification, - # are permitted provided that the following conditions are met: + # Redistribution and use in source and binary forms, with or without + # modification, + # are permitted provided that the following conditions are met: # - # Redistributions of source code must retain the above copyright notice, this - # list of conditions and the following disclaimer. Redistributions in binary - # form must reproduce the above copyright notice, this list of conditions and - # the following disclaimer in the documentation and/or other materials - # provided with the distribution. # - # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - # -------------------------------------------------------------------------------- + # Redistributions of source code must retain the above copyright notice, this + # list of conditions and the following disclaimer. Redistributions in + # binary form must reproduce the above copyright notice, this list of + # conditions and the following disclaimer in the documentation and/or + # other materials provided with the distribution. + # + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # OF THE POSSIBILITY OF SUCH DAMAGE. + # -------------------------------------------------------------------------- 4. Burmese Word Break Dictionary Data (burmesedict.txt) - # Copyright (c) 2014 International Business Machines Corporation - # and others. All Rights Reserved. - # - # This list is part of a project hosted at: - # github.com/kanyawtech/myanmar-karen-word-lists + # Copyright (c) 2014 International Business Machines Corporation + # and others. All Rights Reserved. # - # -------------------------------------------------------------------------------- - # Copyright (c) 2013, LeRoy Benjamin Sharon - # All rights reserved. + # This list is part of a project hosted at: + # github.com/kanyawtech/myanmar-karen-word-lists # - # Redistribution and use in source and binary forms, with or without modification, - # are permitted provided that the following conditions are met: + # -------------------------------------------------------------------------- + # Copyright (c) 2013, LeRoy Benjamin Sharon + # All rights reserved. # - # Redistributions of source code must retain the above copyright notice, this - # list of conditions and the following disclaimer. + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: Redistributions of source code must retain the above + # copyright notice, this list of conditions and the following + # disclaimer. Redistributions in binary form must reproduce the + # above copyright notice, this list of conditions and the following + # disclaimer in the documentation and/or other materials provided + # with the distribution. # - # Redistributions in binary form must reproduce the above copyright notice, this - # list of conditions and the following disclaimer in the documentation and/or - # other materials provided with the distribution. + # Neither the name Myanmar Karen Word Lists, nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. # - # Neither the name Myanmar Karen Word Lists, nor the names of its - # contributors may be used to endorse or promote products derived from - # this software without specific prior written permission. - # - # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - # -------------------------------------------------------------------------------- + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + # SUCH DAMAGE. + # -------------------------------------------------------------------------- 5. Time Zone Database - ICU uses the public domain data and code derived from - Time Zone Database for its time zone support. The ownership of the TZ database is explained - in BCP 175: Procedure for Maintaining the Time Zone + + ICU uses the public domain data and code derived from Time Zone + Database for its time zone support. The ownership of the TZ database + is explained in BCP 175: Procedure for Maintaining the Time Zone Database section 7. - 7. Database Ownership - - The TZ database itself is not an IETF Contribution or an IETF - document. Rather it is a pre-existing and regularly updated work - that is in the public domain, and is intended to remain in the public - domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do not apply - to the TZ Database or contributions that individuals make to it. - Should any claims be made and substantiated against the TZ Database, - the organization that is providing the IANA Considerations defined in - this RFC, under the memorandum of understanding with the IETF, - currently ICANN, may act in accordance with all competent court - orders. No ownership claims will be made by ICANN or the IETF Trust - on the database or the code. Any person making a contribution to the - database or code waives all rights to future claims in that - contribution or in the TZ Database. + # 7. Database Ownership + # + # The TZ database itself is not an IETF Contribution or an IETF + # document. Rather it is a pre-existing and regularly updated work + # that is in the public domain, and is intended to remain in the + # public domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do + # not apply to the TZ Database or contributions that individuals make + # to it. Should any claims be made and substantiated against the TZ + # Database, the organization that is providing the IANA + # Considerations defined in this RFC, under the memorandum of + # understanding with the IETF, currently ICANN, may act in accordance + # with all competent court orders. No ownership claims will be made + # by ICANN or the IETF Trust on the database or the code. Any person + # making a contribution to the database or code waives all rights to + # future claims in that contribution or in the TZ Database. """ - libuv, located at deps/uv, is licensed as follows: diff --git a/tools/license-builder.sh b/tools/license-builder.sh index 5d6b810e123..3d587227b41 100755 --- a/tools/license-builder.sh +++ b/tools/license-builder.sh @@ -22,7 +22,7 @@ $(echo -e "$3" | sed -e 's/^/ /' -e 's/^ $//' -e 's/ *$//' | sed -e '/./,$ } -if ! [ -f "${rootdir}/deps/icu/license.html" ]; then +if ! [ -d "${rootdir}/deps/icu/" ]; then echo "ICU not installed, run configure to download it, e.g. ./configure --with-intl=small-icu --download=icu" exit 1 fi @@ -32,9 +32,21 @@ fi addlicense "c-ares" "deps/cares" \ "$(sed -e '/^ \*\/$/,$d' -e '/^$/d' -e 's/^[/ ]\* *//' ${rootdir}/deps/cares/src/ares_init.c)" addlicense "HTTP Parser" "deps/http_parser" "$(cat deps/http_parser/LICENSE-MIT)" -addlicense "ICU" "deps/icu" \ - "$(sed -e '1,/ICU License - ICU 1\.8\.1 and later/d' -e :a \ - -e 's/<[^>]*>//g;s/ / /g;s/ +$//;/]*>//g;s/ / /g;s/ +$//;/]*>//g;s/ / /g;s/ +$//;/ Date: Mon, 4 Apr 2016 15:35:29 -0400 Subject: [PATCH 30/48] crypto: better error message for createHash calling digest or update on a hash object after digest has been called now gives a topical error message instead of an error message saying that the hash failed to initialize. PR-URL: https://github.com/nodejs/node/pull/6042 Reviewed-By: Brian White Reviewed-By: James M Snell --- src/node_crypto.cc | 13 ++++++++++++- src/node_crypto.h | 1 + test/parallel/test-crypto-hash.js | 12 ++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 2b0f6e6fbb2..1e9226c9256 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -3676,6 +3676,7 @@ bool Hash::HashInit(const char* hash_type) { return false; } initialised_ = true; + finalized_ = false; return true; } @@ -3695,6 +3696,13 @@ void Hash::HashUpdate(const FunctionCallbackInfo& args) { THROW_AND_RETURN_IF_NOT_STRING_OR_BUFFER(args[0], "Data"); + if (!hash->initialised_) { + return env->ThrowError("Not initialized"); + } + if (hash->finalized_) { + return env->ThrowError("Digest already called"); + } + // Only copy the data if we have to, because it's a string bool r; if (args[0]->IsString()) { @@ -3722,6 +3730,9 @@ void Hash::HashDigest(const FunctionCallbackInfo& args) { if (!hash->initialised_) { return env->ThrowError("Not initialized"); } + if (hash->finalized_) { + return env->ThrowError("Digest already called"); + } enum encoding encoding = BUFFER; if (args.Length() >= 1) { @@ -3735,7 +3746,7 @@ void Hash::HashDigest(const FunctionCallbackInfo& args) { EVP_DigestFinal_ex(&hash->mdctx_, md_value, &md_len); EVP_MD_CTX_cleanup(&hash->mdctx_); - hash->initialised_ = false; + hash->finalized_ = true; Local rc = StringBytes::Encode(env->isolate(), reinterpret_cast(md_value), diff --git a/src/node_crypto.h b/src/node_crypto.h index 66c50efa2c0..01c16b39b51 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -538,6 +538,7 @@ class Hash : public BaseObject { EVP_MD_CTX mdctx_; /* coverity[member_decl] */ const EVP_MD* md_; /* coverity[member_decl] */ bool initialised_; + bool finalized_; }; class SignBase : public BaseObject { diff --git a/test/parallel/test-crypto-hash.js b/test/parallel/test-crypto-hash.js index fce11eca046..b5fc7e881c3 100644 --- a/test/parallel/test-crypto-hash.js +++ b/test/parallel/test-crypto-hash.js @@ -98,3 +98,15 @@ assert.equal( assert.notEqual( hutf8, crypto.createHash('sha512').update('УТФ-8 text', 'binary').digest('hex')); + +var h3 = crypto.createHash('sha256'); +h3.digest(); +assert.throws(function() { + h3.digest(); +}, + /Digest already called/); + +assert.throws(function() { + h3.update('foo'); +}, + /Digest already called/); From cf29b2f815967ab9e5638dd6e3138a040fa775f9 Mon Sep 17 00:00:00 2001 From: Nikolai Vavilov Date: Sat, 2 Apr 2016 16:44:18 +0300 Subject: [PATCH 31/48] doc: document intention and dangers of fs module Buffer API PR-URL: https://github.com/nodejs/node/pull/6020 Reviewed-By: James M Snell --- doc/api/fs.markdown | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/api/fs.markdown b/doc/api/fs.markdown index 8a05ffa3c23..22eb14c9dab 100644 --- a/doc/api/fs.markdown +++ b/doc/api/fs.markdown @@ -94,6 +94,18 @@ Error: EISDIR, read ``` +## Buffer API + +`fs` functions support passing and receiving paths as both strings +and Buffers. The latter is intended to make it possible to work with +filesystems that allow for non-UTF-8 filenames. For most typical +uses, working with paths as Buffers will be unnecessary, as the string +API converts to and from UTF-8 automatically. + +*Note* that on certain file systems (such as NTFS and HFS+) filenames +will always be encoded as UTF-8. On such file systems, passing +non-UTF-8 encoded Buffers to `fs` functions will not work as expected. + ## Class: fs.FSWatcher Objects returned from `fs.watch()` are of this type. From a974e852c6882c911ca6e3b647f1587400282413 Mon Sep 17 00:00:00 2001 From: Matthew Douglass Date: Thu, 31 Mar 2016 22:59:21 -0700 Subject: [PATCH 32/48] doc: fix http response event, Agent#getName Removes the options block from the http 'response' event and attaches it to Agent#getName where it belongs. Removes socketPath and documents localAddress option. PR-URL: https://github.com/nodejs/node/pull/5993 Reviewed-By: James M Snell --- doc/api/http.markdown | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/doc/api/http.markdown b/doc/api/http.markdown index 124bd029fd5..68f0bd6d735 100644 --- a/doc/api/http.markdown +++ b/doc/api/http.markdown @@ -152,6 +152,13 @@ connection can be reused. In the http agent, this returns CA, cert, ciphers, and other HTTPS/TLS-specific options that determine socket reusability. +Options: + +- `host`: A domain name or IP address of the server to issue the request to. +- `port`: Port of remote server. +- `localAddress`: Local interface to bind for network connections when issuing + the request. + ### agent.maxFreeSockets By default set to 256. For Agents supporting HTTP KeepAlive, this @@ -303,12 +310,6 @@ the client should send the request body. Emitted when a response is received to this request. This event is emitted only once. The `response` argument will be an instance of [`http.IncomingMessage`][]. -Options: - -- `host`: A domain name or IP address of the server to issue the request to. -- `port`: Port of remote server. -- `socketPath`: Unix Domain Socket (use one of host:port or socketPath) - ### Event: 'socket' `function (socket) { }` From 4c234df264195b4cbd63fc5593e6e3468844f904 Mon Sep 17 00:00:00 2001 From: Igor Klopov Date: Sun, 27 Mar 2016 20:12:35 +0300 Subject: [PATCH 33/48] doc: path.resolve ignores zero-length strings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/nodejs/node/blob/master/lib/path.js#L187 https://github.com/nodejs/node/blob/master/lib/path.js#L1189 PR-URL: https://github.com/nodejs/node/pull/5928 Reviewed-By: Benjamin Gruenbaum Reviewed-By: Robert Jefe Lindstädt Reviewed-By: James M Snell --- doc/api/path.markdown | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/doc/api/path.markdown b/doc/api/path.markdown index 9188e042d80..49cff7a8beb 100644 --- a/doc/api/path.markdown +++ b/doc/api/path.markdown @@ -294,7 +294,8 @@ If `to` isn't already absolute `from` arguments are prepended in right to left order, until an absolute path is found. If after using all `from` paths still no absolute path is found, the current working directory is used as well. The resulting path is normalized, and trailing slashes are removed unless the path -gets resolved to the root directory. +gets resolved to the root directory. Empty string `from` arguments are +ignored. Another way to think of it is as a sequence of `cd` commands in a shell. @@ -329,9 +330,6 @@ path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif') // '/home/myself/node/wwwroot/static_files/gif/image.gif' ``` -*Note:* If the arguments to `resolve` have zero-length strings then the current - working directory will be used instead of them. - ## path.sep The platform-specific file separator. `'\\'` or `'/'`. From 71801b773aa79bdc7d04c0037c449706a4273b5c Mon Sep 17 00:00:00 2001 From: William Kapke Date: Mon, 18 Apr 2016 17:01:51 +0000 Subject: [PATCH 34/48] doc: DCO anchor that doesn't change PR-URL: https://github.com/nodejs/node/pull/6257 Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e37da91ce8a..842149249b4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -173,6 +173,7 @@ to address, apply your changes in a separate commit and push that to your feature branch. Post a comment in the pull request afterwards; GitHub does not send out notifications when you add commits. + ## Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: From 9a9beefe23ddd9550f04aa4f15c50bd3fdb146dd Mon Sep 17 00:00:00 2001 From: abouthiroppy Date: Fri, 15 Apr 2016 07:23:19 +0900 Subject: [PATCH 35/48] doc: replace functions with arrow functions PR-URL: https://github.com/nodejs/node/pull/6203 Reviewed-By: James M Snell --- doc/api/errors.markdown | 2 +- doc/api/vm.markdown | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/api/errors.markdown b/doc/api/errors.markdown index 0dfe520e35c..bb83ef1320a 100644 --- a/doc/api/errors.markdown +++ b/doc/api/errors.markdown @@ -410,7 +410,7 @@ allowable type. For example, passing a function to a parameter which expects a string would be considered a TypeError. ```js -require('url').parse(function() { }); +require('url').parse(() => { }); // throws TypeError, since it expected a string ``` diff --git a/doc/api/vm.markdown b/doc/api/vm.markdown index a9b5463b3f2..e4a142e930e 100644 --- a/doc/api/vm.markdown +++ b/doc/api/vm.markdown @@ -222,7 +222,7 @@ context. The primary use case is to get access to the V8 debug object: ```js const Debug = vm.runInDebugContext('Debug'); -Debug.scripts().forEach(function(script) { console.log(script.name); }); +Debug.scripts().forEach((script) => { console.log(script.name); }); ``` Note that the debug context and object are intrinsically tied to V8's debugger From c1d82ac2ff15594840e2a1b9531b506ae067ed27 Mon Sep 17 00:00:00 2001 From: Ilya Shaisultanov Date: Sun, 16 Aug 2015 20:35:38 -0700 Subject: [PATCH 36/48] assert: respect assert.doesNotThrow message. Special handling to detect when user has supplied a custom message. Added a test for user message. When testing if `actual` value is an error use `util.isError` instead of `instanceof`. Fixes: https://github.com/nodejs/node/issues/2385 PR-URL: https://github.com/nodejs/node/pull/2407 Reviewed-By: James M Snell --- lib/assert.js | 9 ++++++++- test/parallel/test-assert.js | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/assert.js b/lib/assert.js index b4de551e280..7fc9e0c3426 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -330,7 +330,14 @@ function _throws(shouldThrow, block, expected, message) { fail(actual, expected, 'Missing expected exception' + message); } - if (!shouldThrow && expectedException(actual, expected)) { + const userProvidedMessage = typeof message === 'string'; + const isUnwantedException = !shouldThrow && util.isError(actual); + const isUnexpectedException = !shouldThrow && actual && !expected; + + if ((isUnwantedException && + userProvidedMessage && + expectedException(actual, expected)) || + isUnexpectedException) { fail(actual, expected, 'Got unwanted exception' + message); } diff --git a/test/parallel/test-assert.js b/test/parallel/test-assert.js index 2f4b757f4ec..e537bc3c1d7 100644 --- a/test/parallel/test-assert.js +++ b/test/parallel/test-assert.js @@ -321,6 +321,11 @@ assert.throws(function() {assert.ifError(new Error('test error'));}); assert.doesNotThrow(function() {assert.ifError(null);}); assert.doesNotThrow(function() {assert.ifError();}); +assert.throws(() => { + assert.doesNotThrow(makeBlock(thrower, Error), 'user message'); +}, /Got unwanted exception. user message/, + 'a.doesNotThrow ignores user message'); + // make sure that validating using constructor really works threw = false; try { From 31600735f40e02935b936802ff42d66d49e9769b Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Fri, 15 Apr 2016 21:21:12 -0700 Subject: [PATCH 37/48] lib,test,tools: alignment on variable assignments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correct alignment on variable assignments that span multiple lines in preparation for lint rule to enforce such alignment. PR-URL: https://github.com/nodejs/node/pull/6242 Reviewed-By: Ben Noordhuis Reviewed-By: Johan Bergström Reviewed-By: James M Snell --- lib/child_process.js | 7 ++- lib/repl.js | 4 +- lib/util.js | 9 ++- lib/zlib.js | 4 +- test/parallel/test-buffer-alloc.js | 40 ++++++------ test/parallel/test-buffer.js | 40 ++++++------ test/parallel/test-cluster-worker-exit.js | 2 +- test/parallel/test-cluster-worker-kill.js | 2 +- ...main-no-error-handler-abort-on-uncaught.js | 4 +- test/parallel/test-error-reporting.js | 2 +- test/parallel/test-fs-append-file-sync.js | 12 ++-- test/parallel/test-http-1.0.js | 32 +++++----- test/parallel/test-path-parse-format.js | 5 +- test/parallel/test-path.js | 36 ++++++----- .../test-readline-undefined-columns.js | 4 +- test/parallel/test-tls-cert-regression.js | 43 +++++++------ test/parallel/test-tls-econnreset.js | 63 ++++++++++--------- test/parallel/test-tls-parse-cert-string.js | 6 +- test/parallel/test-vm-static-this.js | 4 +- test/parallel/test-zlib-from-string.js | 47 +++++++------- test/parallel/test-zlib-truncated.js | 17 ++--- test/parallel/test-zlib.js | 6 +- test/sequential/test-stdin-from-file.js | 2 +- test/sequential/test-vm-timeout-rethrow.js | 4 +- tools/doc/type-parser.js | 4 +- 25 files changed, 210 insertions(+), 189 deletions(-) diff --git a/lib/child_process.js b/lib/child_process.js index d6b029b7a50..81fb8c1fcd0 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -463,9 +463,10 @@ function checkExecSyncError(ret) { ret.error = null; if (!err) { - var msg = 'Command failed: ' + - (ret.cmd ? ret.cmd : ret.args.join(' ')) + - (ret.stderr ? '\n' + ret.stderr.toString() : ''); + var msg = 'Command failed: '; + msg += ret.cmd || ret.args.join(' '); + if (ret.stderr) + msg += '\n' + ret.stderr.toString(); err = new Error(msg); } diff --git a/lib/repl.js b/lib/repl.js index d802ff304c0..2c952cfbf73 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -67,8 +67,8 @@ exports.writer = util.inspect; exports._builtinLibs = internalModule.builtinLibs; -const BLOCK_SCOPED_ERROR = 'Block-scoped declarations (let, ' + - 'const, function, class) not yet supported outside strict mode'; +const BLOCK_SCOPED_ERROR = 'Block-scoped declarations (let, const, function, ' + + 'class) not yet supported outside strict mode'; class LineParser { diff --git a/lib/util.js b/lib/util.js index 42661608ddf..63d6d0f3c86 100644 --- a/lib/util.js +++ b/lib/util.js @@ -497,9 +497,12 @@ function formatPrimitive(ctx, value) { var type = typeof value; if (type === 'string') { - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; + var simple = '\'' + + JSON.stringify(value) + .replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + + '\''; return ctx.stylize(simple, 'string'); } if (type === 'number') diff --git a/lib/zlib.js b/lib/zlib.js index a786a0c9118..4a7c1ef153a 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -6,8 +6,8 @@ const binding = process.binding('zlib'); const util = require('util'); const assert = require('assert').ok; const kMaxLength = require('buffer').kMaxLength; -const kRangeErrorMessage = 'Cannot create final Buffer. ' + - 'It would be larger than 0x' + kMaxLength.toString(16) + ' bytes'; +const kRangeErrorMessage = 'Cannot create final Buffer. It would be larger ' + + 'than 0x' + kMaxLength.toString(16) + ' bytes'; // zlib doesn't provide these, so kludge them in following the same // const naming scheme zlib uses. diff --git a/test/parallel/test-buffer-alloc.js b/test/parallel/test-buffer-alloc.js index 131fcb112f5..2d675245d2e 100644 --- a/test/parallel/test-buffer-alloc.js +++ b/test/parallel/test-buffer-alloc.js @@ -535,17 +535,17 @@ assert.equal('TWFu', (Buffer.from('Man')).toString('base64')); { // big example const quote = 'Man is distinguished, not only by his reason, but by this ' + - 'singular passion from other animals, which is a lust ' + - 'of the mind, that by a perseverance of delight in the ' + - 'continued and indefatigable generation of knowledge, exceeds ' + - 'the short vehemence of any carnal pleasure.'; + 'singular passion from other animals, which is a lust ' + + 'of the mind, that by a perseverance of delight in the ' + + 'continued and indefatigable generation of knowledge, ' + + 'exceeds the short vehemence of any carnal pleasure.'; const expected = 'TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb' + - '24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBh' + - 'bmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnk' + - 'gYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIG' + - 'FuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBle' + - 'GNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVh' + - 'c3VyZS4='; + '24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlci' + + 'BhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQ' + + 'gYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu' + + 'dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZ' + + 'GdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm' + + '5hbCBwbGVhc3VyZS4='; assert.equal(expected, (Buffer.from(quote)).toString('base64')); let b = Buffer.allocUnsafe(1024); @@ -555,11 +555,11 @@ assert.equal('TWFu', (Buffer.from('Man')).toString('base64')); // check that the base64 decoder ignores whitespace const expectedWhite = expected.slice(0, 60) + ' \n' + - expected.slice(60, 120) + ' \n' + - expected.slice(120, 180) + ' \n' + - expected.slice(180, 240) + ' \n' + - expected.slice(240, 300) + '\n' + - expected.slice(300, 360) + '\n'; + expected.slice(60, 120) + ' \n' + + expected.slice(120, 180) + ' \n' + + expected.slice(180, 240) + ' \n' + + expected.slice(240, 300) + '\n' + + expected.slice(300, 360) + '\n'; b = Buffer.allocUnsafe(1024); bytesWritten = b.write(expectedWhite, 0, 'base64'); assert.equal(quote.length, bytesWritten); @@ -573,11 +573,11 @@ assert.equal('TWFu', (Buffer.from('Man')).toString('base64')); // check that the base64 decoder ignores illegal chars const expectedIllegal = expected.slice(0, 60) + ' \x80' + - expected.slice(60, 120) + ' \xff' + - expected.slice(120, 180) + ' \x00' + - expected.slice(180, 240) + ' \x98' + - expected.slice(240, 300) + '\x03' + - expected.slice(300, 360); + expected.slice(60, 120) + ' \xff' + + expected.slice(120, 180) + ' \x00' + + expected.slice(180, 240) + ' \x98' + + expected.slice(240, 300) + '\x03' + + expected.slice(300, 360); b = Buffer.from(expectedIllegal, 'base64'); assert.equal(quote.length, b.length); assert.equal(quote, b.toString('ascii', 0, quote.length)); diff --git a/test/parallel/test-buffer.js b/test/parallel/test-buffer.js index 5f9180aadb4..2d54a93f1fc 100644 --- a/test/parallel/test-buffer.js +++ b/test/parallel/test-buffer.js @@ -533,17 +533,17 @@ assert.equal('TWFu', (new Buffer('Man')).toString('base64')); { // big example const quote = 'Man is distinguished, not only by his reason, but by this ' + - 'singular passion from other animals, which is a lust ' + - 'of the mind, that by a perseverance of delight in the ' + - 'continued and indefatigable generation of knowledge, exceeds ' + - 'the short vehemence of any carnal pleasure.'; + 'singular passion from other animals, which is a lust ' + + 'of the mind, that by a perseverance of delight in the ' + + 'continued and indefatigable generation of knowledge, ' + + 'exceeds the short vehemence of any carnal pleasure.'; const expected = 'TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb' + - '24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBh' + - 'bmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnk' + - 'gYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIG' + - 'FuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBle' + - 'GNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVh' + - 'c3VyZS4='; + '24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlci' + + 'BhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQ' + + 'gYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu' + + 'dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZ' + + 'GdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm' + + '5hbCBwbGVhc3VyZS4='; assert.equal(expected, (new Buffer(quote)).toString('base64')); let b = new Buffer(1024); @@ -553,11 +553,11 @@ assert.equal('TWFu', (new Buffer('Man')).toString('base64')); // check that the base64 decoder ignores whitespace const expectedWhite = expected.slice(0, 60) + ' \n' + - expected.slice(60, 120) + ' \n' + - expected.slice(120, 180) + ' \n' + - expected.slice(180, 240) + ' \n' + - expected.slice(240, 300) + '\n' + - expected.slice(300, 360) + '\n'; + expected.slice(60, 120) + ' \n' + + expected.slice(120, 180) + ' \n' + + expected.slice(180, 240) + ' \n' + + expected.slice(240, 300) + '\n' + + expected.slice(300, 360) + '\n'; b = new Buffer(1024); bytesWritten = b.write(expectedWhite, 0, 'base64'); assert.equal(quote.length, bytesWritten); @@ -571,11 +571,11 @@ assert.equal('TWFu', (new Buffer('Man')).toString('base64')); // check that the base64 decoder ignores illegal chars const expectedIllegal = expected.slice(0, 60) + ' \x80' + - expected.slice(60, 120) + ' \xff' + - expected.slice(120, 180) + ' \x00' + - expected.slice(180, 240) + ' \x98' + - expected.slice(240, 300) + '\x03' + - expected.slice(300, 360); + expected.slice(60, 120) + ' \xff' + + expected.slice(120, 180) + ' \x00' + + expected.slice(180, 240) + ' \x98' + + expected.slice(240, 300) + '\x03' + + expected.slice(300, 360); b = new Buffer(expectedIllegal, 'base64'); assert.equal(quote.length, b.length); assert.equal(quote, b.toString('ascii', 0, quote.length)); diff --git a/test/parallel/test-cluster-worker-exit.js b/test/parallel/test-cluster-worker-exit.js index ccb213f0df9..60c80ec9385 100644 --- a/test/parallel/test-cluster-worker-exit.js +++ b/test/parallel/test-cluster-worker-exit.js @@ -107,7 +107,7 @@ function checkResults(expected_results, results) { const expected = expected_results[k]; var msg = (expected[1] || '') + - (' [expected: ' + expected[0] + ' / actual: ' + actual + ']'); + (' [expected: ' + expected[0] + ' / actual: ' + actual + ']'); if (expected && expected.length) { assert.equal(actual, expected[0], msg); diff --git a/test/parallel/test-cluster-worker-kill.js b/test/parallel/test-cluster-worker-kill.js index 1f44c93488b..7c2465f9a46 100644 --- a/test/parallel/test-cluster-worker-kill.js +++ b/test/parallel/test-cluster-worker-kill.js @@ -90,7 +90,7 @@ function checkResults(expected_results, results) { const expected = expected_results[k]; var msg = (expected[1] || '') + - (' [expected: ' + expected[0] + ' / actual: ' + actual + ']'); + (' [expected: ' + expected[0] + ' / actual: ' + actual + ']'); if (expected && expected.length) { assert.equal(actual, expected[0], msg); } else { diff --git a/test/parallel/test-domain-no-error-handler-abort-on-uncaught.js b/test/parallel/test-domain-no-error-handler-abort-on-uncaught.js index 2ecb4ffb817..2fef72db00b 100644 --- a/test/parallel/test-domain-no-error-handler-abort-on-uncaught.js +++ b/test/parallel/test-domain-no-error-handler-abort-on-uncaught.js @@ -160,8 +160,8 @@ if (process.argv[2] === 'child') { child.on('exit', function onExit(exitCode, signal) { const errMsg = 'Test at index ' + testIndex + ' should have aborted ' + - 'but instead exited with exit code ' + exitCode + ' and signal ' + - signal; + 'but instead exited with exit code ' + exitCode + + ' and signal ' + signal; assert(common.nodeProcessAborted(exitCode, signal), errMsg); }); }); diff --git a/test/parallel/test-error-reporting.js b/test/parallel/test-error-reporting.js index b5b70eeb3b2..567642d3e83 100644 --- a/test/parallel/test-error-reporting.js +++ b/test/parallel/test-error-reporting.js @@ -8,7 +8,7 @@ var exits = 0; function errExec(script, callback) { var cmd = '"' + process.argv[0] + '" "' + - path.join(common.fixturesDir, script) + '"'; + path.join(common.fixturesDir, script) + '"'; return exec(cmd, function(err, stdout, stderr) { // There was some error assert.ok(err); diff --git a/test/parallel/test-fs-append-file-sync.js b/test/parallel/test-fs-append-file-sync.js index 576c406af26..d337e6ff326 100644 --- a/test/parallel/test-fs-append-file-sync.js +++ b/test/parallel/test-fs-append-file-sync.js @@ -8,12 +8,12 @@ var currentFileData = 'ABCD'; var num = 220; var data = '南越国是前203年至前111年存在于岭南地区的一个国家,国都位于番禺,疆域包括今天中国的广东、' + - '广西两省区的大部份地区,福建省、湖南、贵州、云南的一小部份地区和越南的北部。' + - '南越国是秦朝灭亡后,由南海郡尉赵佗于前203年起兵兼并桂林郡和象郡后建立。' + - '前196年和前179年,南越国曾先后两次名义上臣属于西汉,成为西汉的“外臣”。前112年,' + - '南越国末代君主赵建德与西汉发生战争,被汉武帝于前111年所灭。南越国共存在93年,' + - '历经五代君主。南越国是岭南地区的第一个有记载的政权国家,采用封建制和郡县制并存的制度,' + - '它的建立保证了秦末乱世岭南地区社会秩序的稳定,有效的改善了岭南地区落后的政治、##济现状。\n'; + '广西两省区的大部份地区,福建省、湖南、贵州、云南的一小部份地区和越南的北部。' + + '南越国是秦朝灭亡后,由南海郡尉赵佗于前203年起兵兼并桂林郡和象郡后建立。' + + '前196年和前179年,南越国曾先后两次名义上臣属于西汉,成为西汉的“外臣”。前112年,' + + '南越国末代君主赵建德与西汉发生战争,被汉武帝于前111年所灭。南越国共存在93年,' + + '历经五代君主。南越国是岭南地区的第一个有记载的政权国家,采用封建制和郡县制并存的制度,' + + '它的建立保证了秦末乱世岭南地区社会秩序的稳定,有效的改善了岭南地区落后的政治、##济现状。\n'; common.refreshTmpDir(); diff --git a/test/parallel/test-http-1.0.js b/test/parallel/test-http-1.0.js index b4cb62534c4..facf5c98eac 100644 --- a/test/parallel/test-http-1.0.js +++ b/test/parallel/test-http-1.0.js @@ -88,11 +88,11 @@ function test(handler, request_generator, response_validator) { } function response_validator(server_response, client_got_eof, timed_out) { - var expected_response = ('HTTP/1.1 200 OK\r\n' + - 'Content-Type: text/plain\r\n' + - 'Connection: close\r\n' + - '\r\n' + - 'Hello, world!'); + var expected_response = 'HTTP/1.1 200 OK\r\n' + + 'Content-Type: text/plain\r\n' + + 'Connection: close\r\n' + + '\r\n' + + 'Hello, world!'; assert.equal(expected_response, server_response); assert.equal(true, client_got_eof); @@ -125,17 +125,17 @@ function test(handler, request_generator, response_validator) { } function response_validator(server_response, client_got_eof, timed_out) { - var expected_response = ('HTTP/1.1 200 OK\r\n' + - 'Content-Type: text/plain\r\n' + - 'Connection: close\r\n' + - 'Transfer-Encoding: chunked\r\n' + - '\r\n' + - '7\r\n' + - 'Hello, \r\n' + - '6\r\n' + - 'world!\r\n' + - '0\r\n' + - '\r\n'); + var expected_response = 'HTTP/1.1 200 OK\r\n' + + 'Content-Type: text/plain\r\n' + + 'Connection: close\r\n' + + 'Transfer-Encoding: chunked\r\n' + + '\r\n' + + '7\r\n' + + 'Hello, \r\n' + + '6\r\n' + + 'world!\r\n' + + '0\r\n' + + '\r\n'; assert.equal(expected_response, server_response); assert.equal(true, client_got_eof); diff --git a/test/parallel/test-path-parse-format.js b/test/parallel/test-path-parse-format.js index 5c2684bc6d1..a42794790d1 100644 --- a/test/parallel/test-path-parse-format.js +++ b/test/parallel/test-path-parse-format.js @@ -128,12 +128,11 @@ const trailingTests = [ const failures = []; trailingTests.forEach(function(test) { const parse = test[0]; + const os = parse === path.win32.parse ? 'win32' : 'posix'; test[1].forEach(function(test) { const actual = parse(test[0]); const expected = test[1]; - const fn = 'path.' + - (parse === path.win32.parse ? 'win32' : 'posix') + - '.parse('; + const fn = `path.${os}.parse(`; const message = fn + JSON.stringify(test[0]) + ')' + diff --git a/test/parallel/test-path.js b/test/parallel/test-path.js index b6859f79bc8..e2cfdf5cabf 100644 --- a/test/parallel/test-path.js +++ b/test/parallel/test-path.js @@ -155,13 +155,16 @@ assert.throws(path.win32.dirname.bind(null, {}), TypeError); ].forEach(function(test) { [path.posix.extname, path.win32.extname].forEach(function(extname) { let input = test[0]; - if (extname === path.win32.extname) + let os; + if (extname === path.win32.extname) { input = input.replace(/\//g, '\\'); + os = 'win32'; + } else { + os = 'posix'; + } const actual = extname(input); const expected = test[1]; - const fn = 'path.' + - (extname === path.win32.extname ? 'win32' : 'posix') + - '.extname('; + const fn = `path.${os}.extname(`; const message = fn + JSON.stringify(input) + ')' + '\n expect=' + JSON.stringify(expected) + '\n actual=' + JSON.stringify(actual); @@ -319,11 +322,15 @@ joinTests.forEach(function(test) { // For non-Windows specific tests with the Windows join(), we need to try // replacing the slashes since the non-Windows specific tests' `expected` // use forward slashes - const actualAlt = (join === path.win32.join) ? - actual.replace(/\\/g, '/') : undefined; - const fn = 'path.' + - (join === path.win32.join ? 'win32' : 'posix') + - '.join('; + let actualAlt; + let os; + if (join === path.win32.join) { + actualAlt = actual.replace(/\\/g, '/'); + os = 'win32'; + } else { + os = 'posix'; + } + const fn = `path.${os}.join(`; const message = fn + test[0].map(JSON.stringify).join(',') + ')' + '\n expect=' + JSON.stringify(expected) + '\n actual=' + JSON.stringify(actual); @@ -423,14 +430,14 @@ resolveTests.forEach(function(test) { test[1].forEach(function(test) { const actual = resolve.apply(null, test[0]); let actualAlt; + const os = resolve === path.win32.resolve ? 'win32' : 'posix'; if (resolve === path.win32.resolve && !common.isWindows) actualAlt = actual.replace(/\\/g, '/'); else if (resolve !== path.win32.resolve && common.isWindows) actualAlt = actual.replace(/\//g, '\\'); + const expected = test[1]; - const fn = 'path.' + - (resolve === path.win32.resolve ? 'win32' : 'posix') + - '.resolve('; + const fn = `path.${os}.resolve(`; const message = fn + test[0].map(JSON.stringify).join(',') + ')' + '\n expect=' + JSON.stringify(expected) + '\n actual=' + JSON.stringify(actual); @@ -517,9 +524,8 @@ relativeTests.forEach(function(test) { test[1].forEach(function(test) { const actual = relative(test[0], test[1]); const expected = test[2]; - const fn = 'path.' + - (relative === path.win32.relative ? 'win32' : 'posix') + - '.relative('; + const os = relative === path.win32.relative ? 'win32' : 'posix'; + const fn = `path.${os}.relative(`; const message = fn + test.slice(0, 2).map(JSON.stringify).join(',') + ')' + diff --git a/test/parallel/test-readline-undefined-columns.js b/test/parallel/test-readline-undefined-columns.js index 24f138f46bc..f3197ff59a9 100644 --- a/test/parallel/test-readline-undefined-columns.js +++ b/test/parallel/test-readline-undefined-columns.js @@ -28,8 +28,8 @@ oStream.on('data', function(data) { oStream.on('end', function() { const expect = 'process.stdout\r\n' + - 'process.stdin\r\n' + - 'process.stderr'; + 'process.stdin\r\n' + + 'process.stderr'; assert(new RegExp(expect).test(output)); }); diff --git a/test/parallel/test-tls-cert-regression.js b/test/parallel/test-tls-cert-regression.js index 45e757e7a3c..1d4625d83fb 100644 --- a/test/parallel/test-tls-cert-regression.js +++ b/test/parallel/test-tls-cert-regression.js @@ -9,26 +9,29 @@ if (!common.hasCrypto) { var tls = require('tls'); -var cert = '-----BEGIN CERTIFICATE-----\n' + - 'MIIBfjCCASgCCQDmmNjAojbDQjANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB\n' + - 'VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0\n' + - 'cyBQdHkgTHRkMCAXDTE0MDExNjE3NTMxM1oYDzIyODcxMDMxMTc1MzEzWjBFMQsw\n' + - 'CQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJu\n' + - 'ZXQgV2lkZ2l0cyBQdHkgTHRkMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPKwlfMX\n' + - '6HGZIt1xm7fna72eWcOYfUfSxSugghvqYgJt2Oi3lH+wsU1O9FzRIVmpeIjDXhbp\n' + - 'Mjsa1HtzSiccPXsCAwEAATANBgkqhkiG9w0BAQUFAANBAHOoKy0NkyfiYH7Ne5ka\n' + - 'uvCyndyeB4d24FlfqEUlkfaWCZlNKRaV9YhLDiEg3BcIreFo4brtKQfZzTRs0GVm\n' + - 'KHg=\n' + - '-----END CERTIFICATE-----'; -var key = '-----BEGIN RSA PRIVATE KEY-----\n' + - 'MIIBPQIBAAJBAPKwlfMX6HGZIt1xm7fna72eWcOYfUfSxSugghvqYgJt2Oi3lH+w\n' + - 'sU1O9FzRIVmpeIjDXhbpMjsa1HtzSiccPXsCAwEAAQJBAM4uU9aJE0OfdE1p/X+K\n' + - 'LrCT3XMdFCJ24GgmHyOURtwDy18upQJecDVdcZp16fjtOPmaW95GoYRyifB3R4I5\n' + - 'RxECIQD7jRM9slCSVV8xp9kOJQNpHjhRQYVGBn+pyllS2sb+RQIhAPb7Y+BIccri\n' + - 'NWnuhwCW8hA7Fkj/kaBdAwyW7L3Tvui/AiEAiqLCovMecre4Yi6GcsQ1b/6mvSmm\n' + - 'IOS+AT6zIfXPTB0CIQCJKGR3ymN/Qw5crL1GQ41cHCQtF9ickOq/lBUW+j976wIh\n' + - 'AOaJnkQrmurlRdePX6LvN/LgGAQoxwovfjcOYNnZsIVY\n' + - '-----END RSA PRIVATE KEY-----'; +var cert = +`-----BEGIN CERTIFICATE----- +MIIBfjCCASgCCQDmmNjAojbDQjANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMCAXDTE0MDExNjE3NTMxM1oYDzIyODcxMDMxMTc1MzEzWjBFMQsw +CQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJu +ZXQgV2lkZ2l0cyBQdHkgTHRkMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPKwlfMX +6HGZIt1xm7fna72eWcOYfUfSxSugghvqYgJt2Oi3lH+wsU1O9FzRIVmpeIjDXhbp +Mjsa1HtzSiccPXsCAwEAATANBgkqhkiG9w0BAQUFAANBAHOoKy0NkyfiYH7Ne5ka +uvCyndyeB4d24FlfqEUlkfaWCZlNKRaV9YhLDiEg3BcIreFo4brtKQfZzTRs0GVm +KHg= +-----END CERTIFICATE-----`; + +var key = +`-----BEGIN RSA PRIVATE KEY----- +MIIBPQIBAAJBAPKwlfMX6HGZIt1xm7fna72eWcOYfUfSxSugghvqYgJt2Oi3lH+w +sU1O9FzRIVmpeIjDXhbpMjsa1HtzSiccPXsCAwEAAQJBAM4uU9aJE0OfdE1p/X+K +LrCT3XMdFCJ24GgmHyOURtwDy18upQJecDVdcZp16fjtOPmaW95GoYRyifB3R4I5 +RxECIQD7jRM9slCSVV8xp9kOJQNpHjhRQYVGBn+pyllS2sb+RQIhAPb7Y+BIccri +NWnuhwCW8hA7Fkj/kaBdAwyW7L3Tvui/AiEAiqLCovMecre4Yi6GcsQ1b/6mvSmm +IOS+AT6zIfXPTB0CIQCJKGR3ymN/Qw5crL1GQ41cHCQtF9ickOq/lBUW+j976wIh +AOaJnkQrmurlRdePX6LvN/LgGAQoxwovfjcOYNnZsIVY +-----END RSA PRIVATE KEY-----`; function test(cert, key, cb) { var server = tls.createServer({ diff --git a/test/parallel/test-tls-econnreset.js b/test/parallel/test-tls-econnreset.js index 78cfbaddb3a..b369ec763a9 100644 --- a/test/parallel/test-tls-econnreset.js +++ b/test/parallel/test-tls-econnreset.js @@ -8,38 +8,41 @@ if (!common.hasCrypto) { } var tls = require('tls'); -var cacert = '-----BEGIN CERTIFICATE-----\n' + - 'MIIBxTCCAX8CAnXnMA0GCSqGSIb3DQEBBQUAMH0xCzAJBgNVBAYTAlVTMQswCQYD\n' + - 'VQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQU3Ryb25n\n' + - 'TG9vcCwgSW5jLjESMBAGA1UECxMJU3Ryb25nT3BzMRowGAYDVQQDExFjYS5zdHJv\n' + - 'bmdsb29wLmNvbTAeFw0xNDAxMTcyMjE1MDdaFw00MTA2MDMyMjE1MDdaMH0xCzAJ\n' + - 'BgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZ\n' + - 'MBcGA1UEChMQU3Ryb25nTG9vcCwgSW5jLjESMBAGA1UECxMJU3Ryb25nT3BzMRow\n' + - 'GAYDVQQDExFjYS5zdHJvbmdsb29wLmNvbTBMMA0GCSqGSIb3DQEBAQUAAzsAMDgC\n' + - 'MQDKbQ6rIR5t1q1v4Ha36jrq0IkyUohy9EYNvLnXUly1PGqxby0ILlAVJ8JawpY9\n' + - 'AVkCAwEAATANBgkqhkiG9w0BAQUFAAMxALA1uS4CqQXRSAyYTfio5oyLGz71a+NM\n' + - '+0AFLBwh5AQjhGd0FcenU4OfHxyDEOJT/Q==\n' + - '-----END CERTIFICATE-----\n'; +var cacert = +`-----BEGIN CERTIFICATE----- +MIIBxTCCAX8CAnXnMA0GCSqGSIb3DQEBBQUAMH0xCzAJBgNVBAYTAlVTMQswCQYD +VQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQU3Ryb25n +TG9vcCwgSW5jLjESMBAGA1UECxMJU3Ryb25nT3BzMRowGAYDVQQDExFjYS5zdHJv +bmdsb29wLmNvbTAeFw0xNDAxMTcyMjE1MDdaFw00MTA2MDMyMjE1MDdaMH0xCzAJ +BgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZ +MBcGA1UEChMQU3Ryb25nTG9vcCwgSW5jLjESMBAGA1UECxMJU3Ryb25nT3BzMRow +GAYDVQQDExFjYS5zdHJvbmdsb29wLmNvbTBMMA0GCSqGSIb3DQEBAQUAAzsAMDgC +MQDKbQ6rIR5t1q1v4Ha36jrq0IkyUohy9EYNvLnXUly1PGqxby0ILlAVJ8JawpY9 +AVkCAwEAATANBgkqhkiG9w0BAQUFAAMxALA1uS4CqQXRSAyYTfio5oyLGz71a+NM ++0AFLBwh5AQjhGd0FcenU4OfHxyDEOJT/Q== +-----END CERTIFICATE-----`; -var cert = '-----BEGIN CERTIFICATE-----\n' + - 'MIIBfDCCATYCAgQaMA0GCSqGSIb3DQEBBQUAMH0xCzAJBgNVBAYTAlVTMQswCQYD\n' + - 'VQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQU3Ryb25n\n' + - 'TG9vcCwgSW5jLjESMBAGA1UECxMJU3Ryb25nT3BzMRowGAYDVQQDExFjYS5zdHJv\n' + - 'bmdsb29wLmNvbTAeFw0xNDAxMTcyMjE1MDdaFw00MTA2MDMyMjE1MDdaMBkxFzAV\n' + - 'BgNVBAMTDnN0cm9uZ2xvb3AuY29tMEwwDQYJKoZIhvcNAQEBBQADOwAwOAIxAMfk\n' + - 'I0LWU15pPUwIQNMnRVhhOibi0TQmAau8FBtgwEfGK01WpfGUaJr1a41K8Uq7xwID\n' + - 'AQABoxkwFzAVBgNVHREEDjAMhwQAAAAAhwR/AAABMA0GCSqGSIb3DQEBBQUAAzEA\n' + - 'cGpYrhkrb7mIh9DNhV0qp7pGjqBzlHqB7KQXw2luLDp//6dyHBMexDCQznkhZKRU\n' + - '-----END CERTIFICATE-----\n'; +var cert = +`-----BEGIN CERTIFICATE----- +MIIBfDCCATYCAgQaMA0GCSqGSIb3DQEBBQUAMH0xCzAJBgNVBAYTAlVTMQswCQYD +VQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQU3Ryb25n +TG9vcCwgSW5jLjESMBAGA1UECxMJU3Ryb25nT3BzMRowGAYDVQQDExFjYS5zdHJv +bmdsb29wLmNvbTAeFw0xNDAxMTcyMjE1MDdaFw00MTA2MDMyMjE1MDdaMBkxFzAV +BgNVBAMTDnN0cm9uZ2xvb3AuY29tMEwwDQYJKoZIhvcNAQEBBQADOwAwOAIxAMfk +I0LWU15pPUwIQNMnRVhhOibi0TQmAau8FBtgwEfGK01WpfGUaJr1a41K8Uq7xwID +AQABoxkwFzAVBgNVHREEDjAMhwQAAAAAhwR/AAABMA0GCSqGSIb3DQEBBQUAAzEA +cGpYrhkrb7mIh9DNhV0qp7pGjqBzlHqB7KQXw2luLDp//6dyHBMexDCQznkhZKRU +-----END CERTIFICATE-----`; -var key = '-----BEGIN RSA PRIVATE KEY-----\n' + - 'MIH0AgEAAjEAx+QjQtZTXmk9TAhA0ydFWGE6JuLRNCYBq7wUG2DAR8YrTVal8ZRo\n' + - 'mvVrjUrxSrvHAgMBAAECMBCGccvSwC2r8Z9Zh1JtirQVxaL1WWpAQfmVwLe0bAgg\n' + - '/JWMU/6hS36TsYyZMxwswQIZAPTAfht/zDLb7Hwgu2twsS1Ra9w/yyvtlwIZANET\n' + - '26votwJAHK1yUrZGA5nnp5qcmQ/JUQIZAII5YV/UUZvF9D/fUplJ7puENPWNY9bN\n' + - 'pQIZAMMwxuS3XiO7two2sQF6W+JTYyX1DPCwAQIZAOYg1TvEGT38k8e8jygv8E8w\n' + - 'YqrWTeQFNQ==\n' + - '-----END RSA PRIVATE KEY-----\n'; +var key = +`-----BEGIN RSA PRIVATE KEY----- +MIH0AgEAAjEAx+QjQtZTXmk9TAhA0ydFWGE6JuLRNCYBq7wUG2DAR8YrTVal8ZRo +mvVrjUrxSrvHAgMBAAECMBCGccvSwC2r8Z9Zh1JtirQVxaL1WWpAQfmVwLe0bAgg +/JWMU/6hS36TsYyZMxwswQIZAPTAfht/zDLb7Hwgu2twsS1Ra9w/yyvtlwIZANET +26votwJAHK1yUrZGA5nnp5qcmQ/JUQIZAII5YV/UUZvF9D/fUplJ7puENPWNY9bN +pQIZAMMwxuS3XiO7two2sQF6W+JTYyX1DPCwAQIZAOYg1TvEGT38k8e8jygv8E8w +YqrWTeQFNQ== +-----END RSA PRIVATE KEY-----`; var ca = [ cert, cacert ]; diff --git a/test/parallel/test-tls-parse-cert-string.js b/test/parallel/test-tls-parse-cert-string.js index 11128783871..6607d6974c9 100644 --- a/test/parallel/test-tls-parse-cert-string.js +++ b/test/parallel/test-tls-parse-cert-string.js @@ -4,8 +4,8 @@ require('../common'); const assert = require('assert'); const tls = require('tls'); -const singles = 'C=US\nST=CA\nL=SF\nO=Node.js Foundation\nOU=Node.js\nCN=ca1\n' - + 'emailAddress=ry@clouds.org'; +const singles = 'C=US\nST=CA\nL=SF\nO=Node.js Foundation\nOU=Node.js\n' + + 'CN=ca1\nemailAddress=ry@clouds.org'; const singlesOut = tls.parseCertString(singles); assert.deepEqual(singlesOut, { C: 'US', @@ -18,7 +18,7 @@ assert.deepEqual(singlesOut, { }); const doubles = 'OU=Domain Control Validated\nOU=PositiveSSL Wildcard\n' + - 'CN=*.nodejs.org'; + 'CN=*.nodejs.org'; const doublesOut = tls.parseCertString(doubles); assert.deepEqual(doublesOut, { OU: [ 'Domain Control Validated', 'PositiveSSL Wildcard' ], diff --git a/test/parallel/test-vm-static-this.js b/test/parallel/test-vm-static-this.js index 143e4e12216..a3cf2d820c3 100644 --- a/test/parallel/test-vm-static-this.js +++ b/test/parallel/test-vm-static-this.js @@ -21,8 +21,8 @@ assert.equal(2, global.hello); console.error('pass values'); var code = 'foo = 1;' + - 'bar = 2;' + - 'if (typeof baz !== \'undefined\') throw new Error(\'test fail\');'; + 'bar = 2;' + + 'if (typeof baz !== \'undefined\') throw new Error(\'test fail\');'; global.foo = 2; global.obj = { foo: 0, baz: 3 }; /* eslint-disable no-unused-vars */ diff --git a/test/parallel/test-zlib-from-string.js b/test/parallel/test-zlib-from-string.js index eadfa3d29a6..bff81b78d67 100644 --- a/test/parallel/test-zlib-from-string.js +++ b/test/parallel/test-zlib-from-string.js @@ -5,27 +5,32 @@ require('../common'); var assert = require('assert'); var zlib = require('zlib'); -var inputString = 'ΩΩLorem ipsum dolor sit amet, consectetur adipiscing el' + - 'it. Morbi faucibus, purus at gravida dictum, libero arcu convallis la' + - 'cus, in commodo libero metus eu nisi. Nullam commodo, neque nec porta' + - ' placerat, nisi est fermentum augue, vitae gravida tellus sapien sit ' + - 'amet tellus. Aenean non diam orci. Proin quis elit turpis. Suspendiss' + - 'e non diam ipsum. Suspendisse nec ullamcorper odio. Vestibulum arcu m' + - 'i, sodales non suscipit id, ultrices ut massa. Sed ac sem sit amet ar' + - 'cu malesuada fermentum. Nunc sed. '; -var expectedBase64Deflate = 'eJxdUUtOQzEMvMoc4OndgT0gJCT2buJWlpI4jePeqZfpm' + - 'XAKLRKbLOzx/HK73q6vOrhCunlF1qIDJhNUeW5I2ozT5OkDlKWLJWkncJG5403HQXAkT3' + - 'Jw29B9uIEmToMukglZ0vS6ociBh4JG8sV4oVLEUCitK2kxq1WzPnChHDzsaGKy491Lofo' + - 'AbWh8do43oeuYhB5EPCjcLjzYJo48KrfQBvnJecNFJvHT1+RSQsGoC7dn2t/xjhduTA1N' + - 'WyQIZR0pbHwMDatnD+crPqKSqGPHp1vnlsWM/07ubf7bheF7kqSj84Bm0R1fYTfaK8vqq' + - 'qfKBtNMhe3OZh6N95CTvMX5HJJi4xOVzCgUOIMSLH7wmeOHaFE4RdpnGavKtrB5xzfO/Ll9'; -var expectedBase64Gzip = 'H4sIAAAAAAAAA11RS05DMQy8yhzg6d2BPSAkJPZu4laWkjiN' + - '496pl+mZcAotEpss7PH8crverq86uEK6eUXWogMmE1R5bkjajNPk6QOUpYslaSdwkbnjT' + - 'cdBcCRPcnDb0H24gSZOgy6SCVnS9LqhyIGHgkbyxXihUsRQKK0raTGrVbM+cKEcPOxoYr' + - 'Lj3Uuh+gBtaHx2jjeh65iEHkQ8KNwuPNgmjjwqt9AG+cl5w0Um8dPX5FJCwagLt2fa3/G' + - 'OF25MDU1bJAhlHSlsfAwNq2cP5ys+opKoY8enW+eWxYz/Tu5t/tuF4XuSpKPzgGbRHV9h' + - 'N9ory+qqp8oG00yF7c5mHo33kJO8xfkckmLjE5XMKBQ4gxIsfvCZ44doUThF2mcZq8q2s' + - 'HnHNzRtagj5AQAA'; +var inputString = 'ΩΩLorem ipsum dolor sit amet, consectetur adipiscing elit.' + + ' Morbi faucibus, purus at gravida dictum, libero arcu conv' + + 'allis lacus, in commodo libero metus eu nisi. Nullam commo' + + 'do, neque nec porta placerat, nisi est fermentum augue, vi' + + 'tae gravida tellus sapien sit amet tellus. Aenean non diam' + + ' orci. Proin quis elit turpis. Suspendisse non diam ipsum.' + + ' Suspendisse nec ullamcorper odio. Vestibulum arcu mi, sod' + + 'ales non suscipit id, ultrices ut massa. Sed ac sem sit am' + + 'et arcu malesuada fermentum. Nunc sed. '; +var expectedBase64Deflate = 'eJxdUUtOQzEMvMoc4OndgT0gJCT2buJWlpI4jePeqZfpmXAK' + + 'LRKbLOzx/HK73q6vOrhCunlF1qIDJhNUeW5I2ozT5OkDlKWL' + + 'JWkncJG5403HQXAkT3Jw29B9uIEmToMukglZ0vS6ociBh4JG' + + '8sV4oVLEUCitK2kxq1WzPnChHDzsaGKy491LofoAbWh8do43' + + 'oeuYhB5EPCjcLjzYJo48KrfQBvnJecNFJvHT1+RSQsGoC7dn' + + '2t/xjhduTA1NWyQIZR0pbHwMDatnD+crPqKSqGPHp1vnlsWM' + + '/07ubf7bheF7kqSj84Bm0R1fYTfaK8vqqqfKBtNMhe3OZh6N' + + '95CTvMX5HJJi4xOVzCgUOIMSLH7wmeOHaFE4RdpnGavKtrB5' + + 'xzfO/Ll9'; +var expectedBase64Gzip = 'H4sIAAAAAAAAA11RS05DMQy8yhzg6d2BPSAkJPZu4laWkjiN496' + + 'pl+mZcAotEpss7PH8crverq86uEK6eUXWogMmE1R5bkjajNPk6Q' + + 'OUpYslaSdwkbnjTcdBcCRPcnDb0H24gSZOgy6SCVnS9LqhyIGHg' + + 'kbyxXihUsRQKK0raTGrVbM+cKEcPOxoYrLj3Uuh+gBtaHx2jjeh' + + '65iEHkQ8KNwuPNgmjjwqt9AG+cl5w0Um8dPX5FJCwagLt2fa3/G' + + 'OF25MDU1bJAhlHSlsfAwNq2cP5ys+opKoY8enW+eWxYz/Tu5t/t' + + 'uF4XuSpKPzgGbRHV9hN9ory+qqp8oG00yF7c5mHo33kJO8xfkck' + + 'mLjE5XMKBQ4gxIsfvCZ44doUThF2mcZq8q2sHnHNzRtagj5AQAA'; zlib.deflate(inputString, function(err, buffer) { assert.equal(buffer.toString('base64'), expectedBase64Deflate, diff --git a/test/parallel/test-zlib-truncated.js b/test/parallel/test-zlib-truncated.js index 1798a2ca974..da82acb6575 100644 --- a/test/parallel/test-zlib-truncated.js +++ b/test/parallel/test-zlib-truncated.js @@ -5,14 +5,15 @@ require('../common'); const assert = require('assert'); const zlib = require ('zlib'); -const inputString = 'ΩΩLorem ipsum dolor sit amet, consectetur adipiscing el' + - 'it. Morbi faucibus, purus at gravida dictum, libero arcu convallis la' + - 'cus, in commodo libero metus eu nisi. Nullam commodo, neque nec porta' + - ' placerat, nisi est fermentum augue, vitae gravida tellus sapien sit ' + - 'amet tellus. Aenean non diam orci. Proin quis elit turpis. Suspendiss' + - 'e non diam ipsum. Suspendisse nec ullamcorper odio. Vestibulum arcu m' + - 'i, sodales non suscipit id, ultrices ut massa. Sed ac sem sit amet ar' + - 'cu malesuada fermentum. Nunc sed. '; +const inputString = 'ΩΩLorem ipsum dolor sit amet, consectetur adipiscing eli' + + 't. Morbi faucibus, purus at gravida dictum, libero arcu ' + + 'convallis lacus, in commodo libero metus eu nisi. Nullam' + + ' commodo, neque nec porta placerat, nisi est fermentum a' + + 'ugue, vitae gravida tellus sapien sit amet tellus. Aenea' + + 'n non diam orci. Proin quis elit turpis. Suspendisse non' + + ' diam ipsum. Suspendisse nec ullamcorper odio. Vestibulu' + + 'm arcu mi, sodales non suscipit id, ultrices ut massa. S' + + 'ed ac sem sit amet arcu malesuada fermentum. Nunc sed. '; [ { comp: 'gzip', decomp: 'gunzip', decompSync: 'gunzipSync' }, diff --git a/test/parallel/test-zlib.js b/test/parallel/test-zlib.js index f0b7e7bddca..cd2503b8685 100644 --- a/test/parallel/test-zlib.js +++ b/test/parallel/test-zlib.js @@ -165,9 +165,9 @@ Object.keys(tests).forEach(function(file) { // verify that the same exact buffer comes out the other end. buf.on('data', function(c) { var msg = file + ' ' + - chunkSize + ' ' + - JSON.stringify(opts) + ' ' + - Def.name + ' -> ' + Inf.name; + chunkSize + ' ' + + JSON.stringify(opts) + ' ' + + Def.name + ' -> ' + Inf.name; var ok = true; var testNum = ++done; for (var i = 0; i < Math.max(c.length, test.length); i++) { diff --git a/test/sequential/test-stdin-from-file.js b/test/sequential/test-stdin-from-file.js index 07b044769b3..7d5bd723333 100644 --- a/test/sequential/test-stdin-from-file.js +++ b/test/sequential/test-stdin-from-file.js @@ -9,7 +9,7 @@ var stdoutScript = join(common.fixturesDir, 'echo-close-check.js'); var tmpFile = join(common.fixturesDir, 'stdin.txt'); var cmd = '"' + process.argv[0] + '" "' + stdoutScript + '" < "' + - tmpFile + '"'; + tmpFile + '"'; var string = 'abc\nümlaut.\nsomething else\n' + '南越国是前203年至前111年存在于岭南地区的一个国家,国都位于番禺,' + diff --git a/test/sequential/test-vm-timeout-rethrow.js b/test/sequential/test-vm-timeout-rethrow.js index dd513b5a694..f0f9c0b9c51 100644 --- a/test/sequential/test-vm-timeout-rethrow.js +++ b/test/sequential/test-vm-timeout-rethrow.js @@ -6,8 +6,8 @@ var spawn = require('child_process').spawn; if (process.argv[2] === 'child') { var code = 'var j = 0;\n' + - 'for (var i = 0; i < 1000000; i++) j += add(i, i + 1);\n' + - 'j;'; + 'for (var i = 0; i < 1000000; i++) j += add(i, i + 1);\n' + + 'j;'; var ctx = vm.createContext({ add: function(x, y) { diff --git a/tools/doc/type-parser.js b/tools/doc/type-parser.js index 2e6c5bea919..a5698892b8e 100644 --- a/tools/doc/type-parser.js +++ b/tools/doc/type-parser.js @@ -1,9 +1,9 @@ 'use strict'; const nodeDocUrl = ''; const jsDocUrl = 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/' + - 'Reference/Global_Objects/'; + 'Reference/Global_Objects/'; const jsPrimitiveUrl = 'https://developer.mozilla.org/en-US/docs/Web/' + - 'JavaScript/Data_structures'; + 'JavaScript/Data_structures'; const jsPrimitives = [ 'Number', 'String', 'Boolean', 'Null', 'Symbol' ]; From ca698330ac284bdb8b236edcb4f07daa108b858c Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Fri, 15 Apr 2016 21:22:12 -0700 Subject: [PATCH 38/48] tools: lint for alignment of variable assignments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enforce alignment/indentation on variable assignments that span multiple lines. PR-URL: https://github.com/nodejs/node/pull/6242 Reviewed-By: Ben Noordhuis Reviewed-By: Johan Bergström Reviewed-By: James M Snell --- .eslintrc | 4 +- .../align-multiline-assignment.js | 68 +++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 tools/eslint-rules/align-multiline-assignment.js diff --git a/.eslintrc b/.eslintrc index 8e01cc4c94c..e8496e8560f 100644 --- a/.eslintrc +++ b/.eslintrc @@ -13,7 +13,7 @@ rules: no-duplicate-case: 2 no-empty-character-class: 2 no-ex-assign: 2 - no-extra-boolean-cast : 2 + no-extra-boolean-cast: 2 no-extra-parens: [2, "functions"] no-extra-semi: 2 no-func-assign: 2 @@ -86,7 +86,7 @@ rules: # Custom rules in tools/eslint-rules new-with-error: [2, "Error", "RangeError", "TypeError", "SyntaxError", "ReferenceError"] - + align-multiline-assignment: 2 # Global scoped method and vars globals: diff --git a/tools/eslint-rules/align-multiline-assignment.js b/tools/eslint-rules/align-multiline-assignment.js new file mode 100644 index 00000000000..69f1f33d4d1 --- /dev/null +++ b/tools/eslint-rules/align-multiline-assignment.js @@ -0,0 +1,68 @@ +/** + * @fileoverview Align multiline variable assignments + * @author Rich Trott + */ +'use strict'; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ +function getBinaryExpressionStarts(binaryExpression, starts = []) { + function getStartsFromOneSide(side, starts) { + starts.push(side.loc.start); + if (side.type === 'BinaryExpression') { + starts = getBinaryExpressionStarts(side, starts); + } + return starts; + } + + starts = getStartsFromOneSide(binaryExpression.left, starts); + starts = getStartsFromOneSide(binaryExpression.right, starts); + return starts; +} + +function checkExpressionAlignment(expression) { + if (!expression) + return; + + var msg = ''; + + switch (expression.type) { + case 'BinaryExpression': + var starts = getBinaryExpressionStarts(expression); + var startLine = starts[0].line; + const startColumn = starts[0].column; + starts.forEach((loc) => { + if (loc.line > startLine) { + startLine = loc.line; + if (loc.column !== startColumn) { + msg = 'Misaligned multiline assignment'; + } + } + }); + break; + } + return msg; +} + +function testAssignment(context, node) { + const msg = checkExpressionAlignment(node.right); + if (msg) + context.report(node, msg); +} + +function testDeclaration(context, node) { + node.declarations.forEach((declaration) => { + const msg = checkExpressionAlignment(declaration.init); + // const start = declaration.init.loc.start; + if (msg) + context.report(node, msg); + }); +} + +module.exports = function(context) { + return { + 'AssignmentExpression': (node) => testAssignment(context, node), + 'VariableDeclaration': (node) => testDeclaration(context, node) + }; +}; From dba245f79622c0c5877825f7cd11667be3548e8e Mon Sep 17 00:00:00 2001 From: Brian White Date: Tue, 5 Apr 2016 08:22:32 -0400 Subject: [PATCH 39/48] querystring: don't inherit from Object.prototype This commit safely allows querystring keys that are named the same as properties that are ordinarily inherited from Object.prototype such as __proto__. Additionally, this commit provides a bit of a speed improvement (~25% in the querystring-parse 'manypairs' benchmark) when there are many unique keys. Fixes: https://github.com/nodejs/node/issues/5642 PR-URL: https://github.com/nodejs/node/pull/6055 Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- lib/querystring.js | 8 +++++++- test/parallel/test-querystring.js | 6 ++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/querystring.js b/lib/querystring.js index bacfc4bd704..7999ac33f76 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -5,6 +5,12 @@ const QueryString = exports; const Buffer = require('buffer').Buffer; +// This constructor is used to store parsed query string values. Instantiating +// this is faster than explicitly calling `Object.create(null)` to get a +// "clean" empty object (tested with v8 v4.9). +function ParsedQueryString() {} +ParsedQueryString.prototype = Object.create(null); + // a safe fast alternative to decodeURIComponent QueryString.unescapeBuffer = function(s, decodeSpaces) { @@ -216,7 +222,7 @@ QueryString.parse = QueryString.decode = function(qs, sep, eq, options) { sep = sep || '&'; eq = eq || '='; - const obj = {}; + const obj = new ParsedQueryString(); if (typeof qs !== 'string' || qs.length === 0) { return obj; diff --git a/test/parallel/test-querystring.js b/test/parallel/test-querystring.js index 24992b4c69a..019d922a371 100644 --- a/test/parallel/test-querystring.js +++ b/test/parallel/test-querystring.js @@ -9,6 +9,12 @@ var qs = require('querystring'); // {{{ // [ wonkyQS, canonicalQS, obj ] var qsTestCases = [ + ['__proto__=1', + '__proto__=1', + JSON.parse('{"__proto__":"1"}')], + ['__defineGetter__=asdf', + '__defineGetter__=asdf', + JSON.parse('{"__defineGetter__":"asdf"}')], ['foo=918854443121279438895193', 'foo=918854443121279438895193', {'foo': '918854443121279438895193'}], From e38bade82801645d8cc1010e3f4e9826052244cb Mon Sep 17 00:00:00 2001 From: Brian White Date: Wed, 6 Apr 2016 20:33:28 -0400 Subject: [PATCH 40/48] events: don't inherit from Object.prototype This commit safely allows event names that are named the same as properties that are ordinarily inherited from Object.prototype such as __proto__. Fixes: https://github.com/nodejs/node/issues/728 PR-URL: https://github.com/nodejs/node/pull/6092 Reviewed-By: Evan Lucas Reviewed-By: James M Snell --- lib/events.js | 20 +++++++---- src/node.cc | 4 ++- .../test-events-known-properties.js | 12 ------- ...st-event-emitter-listeners-side-effects.js | 1 - .../test-event-emitter-special-event-names.js | 36 +++++++++++++++++++ 5 files changed, 52 insertions(+), 21 deletions(-) delete mode 100644 test/known_issues/test-events-known-properties.js create mode 100644 test/parallel/test-event-emitter-special-event-names.js diff --git a/lib/events.js b/lib/events.js index a67de552f11..669c0d70ea1 100644 --- a/lib/events.js +++ b/lib/events.js @@ -2,6 +2,12 @@ var domain; +// This constructor is used to store event handlers. Instantiating this is +// faster than explicitly calling `Object.create(null)` to get a "clean" empty +// object (tested with v8 v4.9). +function EventHandlers() {} +EventHandlers.prototype = Object.create(null); + function EventEmitter() { EventEmitter.init.call(this); } @@ -44,7 +50,7 @@ EventEmitter.init = function() { } if (!this._events || this._events === Object.getPrototypeOf(this)._events) { - this._events = {}; + this._events = new EventHandlers(); this._eventsCount = 0; } @@ -211,7 +217,7 @@ EventEmitter.prototype.addListener = function addListener(type, listener) { events = this._events; if (!events) { - events = this._events = {}; + events = this._events = new EventHandlers(); this._eventsCount = 0; } else { // To avoid recursion in the case that type === "newListener"! Before @@ -296,7 +302,7 @@ EventEmitter.prototype.removeListener = if (list === listener || (list.listener && list.listener === listener)) { if (--this._eventsCount === 0) - this._events = {}; + this._events = new EventHandlers(); else { delete events[type]; if (events.removeListener) @@ -319,7 +325,7 @@ EventEmitter.prototype.removeListener = if (list.length === 1) { list[0] = undefined; if (--this._eventsCount === 0) { - this._events = {}; + this._events = new EventHandlers(); return this; } else { delete events[type]; @@ -346,11 +352,11 @@ EventEmitter.prototype.removeAllListeners = // not listening for removeListener, no need to emit if (!events.removeListener) { if (arguments.length === 0) { - this._events = {}; + this._events = new EventHandlers(); this._eventsCount = 0; } else if (events[type]) { if (--this._eventsCount === 0) - this._events = {}; + this._events = new EventHandlers(); else delete events[type]; } @@ -366,7 +372,7 @@ EventEmitter.prototype.removeAllListeners = this.removeAllListeners(key); } this.removeAllListeners('removeListener'); - this._events = {}; + this._events = new EventHandlers(); this._eventsCount = 0; return this; } diff --git a/src/node.cc b/src/node.cc index 081905cfc07..dd427c792e9 100644 --- a/src/node.cc +++ b/src/node.cc @@ -3228,7 +3228,9 @@ void SetupProcessObject(Environment* env, env->SetMethod(process, "_setupDomainUse", SetupDomainUse); // pre-set _events object for faster emit checks - process->Set(env->events_string(), Object::New(env->isolate())); + Local events_obj = Object::New(env->isolate()); + events_obj->SetPrototype(env->context(), Null(env->isolate())); + process->Set(env->events_string(), events_obj); } diff --git a/test/known_issues/test-events-known-properties.js b/test/known_issues/test-events-known-properties.js deleted file mode 100644 index 944fa3da2bb..00000000000 --- a/test/known_issues/test-events-known-properties.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; -// Refs: https://github.com/nodejs/node/issues/728 -const common = require('../common'); -const assert = require('assert'); -const EventEmitter = require('events'); -const ee = new EventEmitter(); - -ee.on('__proto__', common.mustCall((data) => { - assert.strictEqual(data, 42); -})); - -ee.emit('__proto__', 42); diff --git a/test/parallel/test-event-emitter-listeners-side-effects.js b/test/parallel/test-event-emitter-listeners-side-effects.js index 355ec5262c9..a30d1d3d81d 100644 --- a/test/parallel/test-event-emitter-listeners-side-effects.js +++ b/test/parallel/test-event-emitter-listeners-side-effects.js @@ -21,7 +21,6 @@ assert(fl.length === 1); assert(fl[0] === assert.fail); e.listeners('bar'); -assert(!e._events.hasOwnProperty('bar')); e.on('foo', assert.ok); fl = e.listeners('foo'); diff --git a/test/parallel/test-event-emitter-special-event-names.js b/test/parallel/test-event-emitter-special-event-names.js new file mode 100644 index 00000000000..fb3f1b52d9e --- /dev/null +++ b/test/parallel/test-event-emitter-special-event-names.js @@ -0,0 +1,36 @@ +'use strict'; + +const common = require('../common'); +const EventEmitter = require('events'); +const assert = require('assert'); + +const ee = new EventEmitter(); +const handler = () => {}; + +assert.strictEqual(ee._events.hasOwnProperty, undefined); +assert.strictEqual(ee._events.toString, undefined); + +ee.on('__proto__', handler); +ee.on('__defineGetter__', handler); +ee.on('toString', handler); + +assert.deepStrictEqual(ee.eventNames(), [ + '__proto__', + '__defineGetter__', + 'toString' +]); + +assert.deepStrictEqual(ee.listeners('__proto__'), [handler]); +assert.deepStrictEqual(ee.listeners('__defineGetter__'), [handler]); +assert.deepStrictEqual(ee.listeners('toString'), [handler]); + +ee.on('__proto__', common.mustCall(function(val) { + assert.strictEqual(val, 1); +})); +ee.emit('__proto__', 1); + +process.on('__proto__', common.mustCall(function(val) { + assert.strictEqual(val, 1); +})); +process.emit('__proto__', 1); + From c7fef3d3b8763d55a238786b56f91939f10f2c36 Mon Sep 17 00:00:00 2001 From: James Lal Date: Thu, 31 Mar 2016 14:16:30 -0700 Subject: [PATCH 41/48] zlib: fix use after null when calling .close An internal zlib error may cause _handle to be set to null. Close now will check if there is a _handle prior to calling .close on it. PR-URL: https://github.com/nodejs/node/pull/5982 Fixes: https://github.com/nodejs/node/issues/6034 Reviewed-By: Brian White Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig --- lib/zlib.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/zlib.js b/lib/zlib.js index 4a7c1ef153a..3915e5ddabd 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -474,7 +474,10 @@ function _close(engine, callback) { engine._closed = true; - engine._handle.close(); + // Caller may invoke .close after a zlib error (which will null _handle). + if (engine._handle) { + engine._handle.close(); + } } function emitCloseNT(self) { From bf22c71a7ab8417d7cf5c59d9e18e891137abfb8 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 12 Apr 2016 17:22:07 +0200 Subject: [PATCH 42/48] test: fix test-net-settimeout flakiness Wait for the data to be received by the socket before creating the clean-up timer. This way, a possible (though unlikely) `ECONNRESET` error can be avoided. PR-URL: https://github.com/nodejs/node/pull/6166 Reviewed-By: James M Snell Reviewed-By: Benjamin Gruenbaum --- test/parallel/test-net-settimeout.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/test/parallel/test-net-settimeout.js b/test/parallel/test-net-settimeout.js index 76ed7b020fb..db0329deea0 100644 --- a/test/parallel/test-net-settimeout.js +++ b/test/parallel/test-net-settimeout.js @@ -8,22 +8,24 @@ const assert = require('assert'); const T = 100; -const server = net.createServer(function(c) { +const server = net.createServer(common.mustCall((c) => { c.write('hello'); -}); +})); + server.listen(common.PORT); const socket = net.createConnection(common.PORT, 'localhost'); -const s = socket.setTimeout(T, function() { +const s = socket.setTimeout(T, () => { common.fail('Socket timeout event is not expected to fire'); }); assert.ok(s instanceof net.Socket); -socket.setTimeout(0); - -setTimeout(function() { - socket.destroy(); - server.close(); -}, T * 2); +socket.on('data', common.mustCall(() => { + setTimeout(function() { + socket.destroy(); + server.close(); + }, T * 2); +})); +socket.setTimeout(0); From 57f05951770052de107c4771a47ebee6b6f1b6ef Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 15 Apr 2016 09:04:00 +0000 Subject: [PATCH 43/48] test: fix flaky test-http-set-timeout-server Make the servers listen on a free port number picked by the OS to avoid rare `EADDRINUSE` errors on `SmartOS`. Fixes: https://github.com/nodejs/node/issues/6197 PR-URL: https://github.com/nodejs/node/pull/6248 Reviewed-By: Rich Trott Reviewed-By: James M Snell --- test/parallel/test-http-set-timeout-server.js | 55 +++++++++++-------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/test/parallel/test-http-set-timeout-server.js b/test/parallel/test-http-set-timeout-server.js index 67db16d2a26..d530503aa1e 100644 --- a/test/parallel/test-http-set-timeout-server.js +++ b/test/parallel/test-http-set-timeout-server.js @@ -30,7 +30,9 @@ test(function serverTimeout(cb) { var server = http.createServer(function(req, res) { // just do nothing, we should get a timeout event. }); - server.listen(common.PORT); + server.listen(common.mustCall(function() { + http.get({ port: server.address().port }).on('error', function() {}); + })); var s = server.setTimeout(50, function(socket) { caughtTimeout = true; socket.destroy(); @@ -38,7 +40,6 @@ test(function serverTimeout(cb) { cb(); }); assert.ok(s instanceof http.Server); - http.get({ port: common.PORT }).on('error', function() {}); }); test(function serverRequestTimeout(cb) { @@ -56,11 +57,13 @@ test(function serverRequestTimeout(cb) { }); assert.ok(s instanceof http.IncomingMessage); }); - server.listen(common.PORT); - var req = http.request({ port: common.PORT, method: 'POST' }); - req.on('error', function() {}); - req.write('Hello'); - // req is in progress + server.listen(common.mustCall(function() { + var port = server.address().port; + var req = http.request({ port: port, method: 'POST' }); + req.on('error', function() {}); + req.write('Hello'); + // req is in progress + })); }); test(function serverResponseTimeout(cb) { @@ -78,8 +81,10 @@ test(function serverResponseTimeout(cb) { }); assert.ok(s instanceof http.OutgoingMessage); }); - server.listen(common.PORT); - http.get({ port: common.PORT }).on('error', function() {}); + server.listen(common.mustCall(function() { + var port = server.address().port; + http.get({ port: port }).on('error', function() {}); + })); }); test(function serverRequestNotTimeoutAfterEnd(cb) { @@ -104,8 +109,10 @@ test(function serverRequestNotTimeoutAfterEnd(cb) { server.close(); cb(); }); - server.listen(common.PORT); - http.get({ port: common.PORT }).on('error', function() {}); + server.listen(common.mustCall(function() { + var port = server.address().port; + http.get({ port: port }).on('error', function() {}); + })); }); test(function serverResponseTimeoutWithPipeline(cb) { @@ -125,12 +132,14 @@ test(function serverResponseTimeoutWithPipeline(cb) { server.close(); cb(); }); - server.listen(common.PORT); - var c = net.connect({ port: common.PORT, allowHalfOpen: true }, function() { - c.write('GET /1 HTTP/1.1\r\nHost: localhost\r\n\r\n'); - c.write('GET /2 HTTP/1.1\r\nHost: localhost\r\n\r\n'); - c.write('GET /3 HTTP/1.1\r\nHost: localhost\r\n\r\n'); - }); + server.listen(common.mustCall(function() { + var port = server.address().port; + var c = net.connect({ port: port, allowHalfOpen: true }, function() { + c.write('GET /1 HTTP/1.1\r\nHost: localhost\r\n\r\n'); + c.write('GET /2 HTTP/1.1\r\nHost: localhost\r\n\r\n'); + c.write('GET /3 HTTP/1.1\r\nHost: localhost\r\n\r\n'); + }); + })); }); test(function idleTimeout(cb) { @@ -158,9 +167,11 @@ test(function idleTimeout(cb) { cb(); }); assert.ok(s instanceof http.Server); - server.listen(common.PORT); - var c = net.connect({ port: common.PORT, allowHalfOpen: true }, function() { - c.write('GET /1 HTTP/1.1\r\nHost: localhost\r\n\r\n'); - // Keep-Alive - }); + server.listen(common.mustCall(function() { + var port = server.address().port; + var c = net.connect({ port: port, allowHalfOpen: true }, function() { + c.write('GET /1 HTTP/1.1\r\nHost: localhost\r\n\r\n'); + // Keep-Alive + }); + })); }); From 7f144833527a457b92e6f3d118ad7906ee63d4b3 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Tue, 19 Apr 2016 10:47:55 -0400 Subject: [PATCH 44/48] deps: update to http-parser 2.7.0 Adds `2` as a return value of `on_headers_complete`, this mode will be used to fix handling responses to `CONNECT` requests. See: https://github.com/nodejs/node/pull/6198 PR-URL: https://github.com/nodejs/node/pull/6279 Reviewed-By: Brian White Reviewed-By: James M Snell --- deps/http_parser/Makefile | 4 +- deps/http_parser/http_parser.c | 3 + deps/http_parser/http_parser.h | 9 ++- deps/http_parser/test.c | 103 +++++++++++++++++++++++++++------ 4 files changed, 98 insertions(+), 21 deletions(-) diff --git a/deps/http_parser/Makefile b/deps/http_parser/Makefile index 970bdc42635..5f4eb2252f2 100644 --- a/deps/http_parser/Makefile +++ b/deps/http_parser/Makefile @@ -22,14 +22,14 @@ PLATFORM ?= $(shell sh -c 'uname -s | tr "[A-Z]" "[a-z]"') HELPER ?= BINEXT ?= ifeq (darwin,$(PLATFORM)) -SONAME ?= libhttp_parser.2.6.2.dylib +SONAME ?= libhttp_parser.2.7.0.dylib SOEXT ?= dylib else ifeq (wine,$(PLATFORM)) CC = winegcc BINEXT = .exe.so HELPER = wine else -SONAME ?= libhttp_parser.so.2.6.2 +SONAME ?= libhttp_parser.so.2.7.0 SOEXT ?= so endif diff --git a/deps/http_parser/http_parser.c b/deps/http_parser/http_parser.c index d51a2e7bcdf..719617549d0 100644 --- a/deps/http_parser/http_parser.c +++ b/deps/http_parser/http_parser.c @@ -1812,6 +1812,9 @@ size_t http_parser_execute (http_parser *parser, case 0: break; + case 2: + parser->upgrade = 1; + case 1: parser->flags |= F_SKIPBODY; break; diff --git a/deps/http_parser/http_parser.h b/deps/http_parser/http_parser.h index 0cee4cc85b3..105ae510a8a 100644 --- a/deps/http_parser/http_parser.h +++ b/deps/http_parser/http_parser.h @@ -26,8 +26,8 @@ extern "C" { /* Also update SONAME in the Makefile whenever you change these. */ #define HTTP_PARSER_VERSION_MAJOR 2 -#define HTTP_PARSER_VERSION_MINOR 6 -#define HTTP_PARSER_VERSION_PATCH 2 +#define HTTP_PARSER_VERSION_MINOR 7 +#define HTTP_PARSER_VERSION_PATCH 0 #include #if defined(_WIN32) && !defined(__MINGW32__) && \ @@ -77,6 +77,11 @@ typedef struct http_parser_settings http_parser_settings; * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: * chunked' headers that indicate the presence of a body. * + * Returning `2` from on_headers_complete will tell parser that it should not + * expect neither a body nor any futher responses on this connection. This is + * useful for handling responses to a CONNECT request which may not contain + * `Upgrade` or `Connection: upgrade` headers. + * * http_data_cb does not return data chunks. It will be called arbitrarily * many times for each string. E.G. you might get 10 callbacks for "on_url" * each providing just a few characters more data. diff --git a/deps/http_parser/test.c b/deps/http_parser/test.c index 7b01dc346b6..456a78add05 100644 --- a/deps/http_parser/test.c +++ b/deps/http_parser/test.c @@ -2173,6 +2173,20 @@ pause_chunk_complete_cb (http_parser *p) return chunk_complete_cb(p); } +int +connect_headers_complete_cb (http_parser *p) +{ + headers_complete_cb(p); + return 1; +} + +int +connect_message_complete_cb (http_parser *p) +{ + messages[num_messages].should_keep_alive = http_should_keep_alive(parser); + return message_complete_cb(p); +} + static http_parser_settings settings_pause = {.on_message_begin = pause_message_begin_cb ,.on_header_field = pause_header_field_cb @@ -2212,6 +2226,19 @@ static http_parser_settings settings_count_body = ,.on_chunk_complete = chunk_complete_cb }; +static http_parser_settings settings_connect = + {.on_message_begin = message_begin_cb + ,.on_header_field = header_field_cb + ,.on_header_value = header_value_cb + ,.on_url = request_url_cb + ,.on_status = response_status_cb + ,.on_body = dontcall_body_cb + ,.on_headers_complete = connect_headers_complete_cb + ,.on_message_complete = connect_message_complete_cb + ,.on_chunk_header = chunk_header_cb + ,.on_chunk_complete = chunk_complete_cb + }; + static http_parser_settings settings_null = {.on_message_begin = 0 ,.on_header_field = 0 @@ -2275,6 +2302,14 @@ size_t parse_pause (const char *buf, size_t len) return nparsed; } +size_t parse_connect (const char *buf, size_t len) +{ + size_t nparsed; + currently_parsing_eof = (len == 0); + nparsed = http_parser_execute(parser, &settings_connect, buf, len); + return nparsed; +} + static inline int check_str_eq (const struct message *m, const char *prop, @@ -2331,7 +2366,7 @@ do { \ } while(0) int -message_eq (int index, const struct message *expected) +message_eq (int index, int connect, const struct message *expected) { int i; struct message *m = &messages[index]; @@ -2346,8 +2381,10 @@ message_eq (int index, const struct message *expected) MESSAGE_CHECK_STR_EQ(expected, m, response_status); } - MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive); - MESSAGE_CHECK_NUM_EQ(expected, m, message_complete_on_eof); + if (!connect) { + MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive); + MESSAGE_CHECK_NUM_EQ(expected, m, message_complete_on_eof); + } assert(m->message_begin_cb_called); assert(m->headers_complete_cb_called); @@ -2385,16 +2422,22 @@ message_eq (int index, const struct message *expected) MESSAGE_CHECK_NUM_EQ(expected, m, port); } - if (expected->body_size) { + if (connect) { + check_num_eq(m, "body_size", 0, m->body_size); + } else if (expected->body_size) { MESSAGE_CHECK_NUM_EQ(expected, m, body_size); } else { MESSAGE_CHECK_STR_EQ(expected, m, body); } - assert(m->num_chunks == m->num_chunks_complete); - MESSAGE_CHECK_NUM_EQ(expected, m, num_chunks_complete); - for (i = 0; i < m->num_chunks && i < MAX_CHUNKS; i++) { - MESSAGE_CHECK_NUM_EQ(expected, m, chunk_lengths[i]); + if (connect) { + check_num_eq(m, "num_chunks_complete", 0, m->num_chunks_complete); + } else { + assert(m->num_chunks == m->num_chunks_complete); + MESSAGE_CHECK_NUM_EQ(expected, m, num_chunks_complete); + for (i = 0; i < m->num_chunks && i < MAX_CHUNKS; i++) { + MESSAGE_CHECK_NUM_EQ(expected, m, chunk_lengths[i]); + } } MESSAGE_CHECK_NUM_EQ(expected, m, num_headers); @@ -3201,7 +3244,7 @@ test_message (const struct message *message) abort(); } - if(!message_eq(0, message)) abort(); + if(!message_eq(0, 0, message)) abort(); parser_free(); } @@ -3238,7 +3281,7 @@ test_message_count_body (const struct message *message) abort(); } - if(!message_eq(0, message)) abort(); + if(!message_eq(0, 0, message)) abort(); parser_free(); } @@ -3589,9 +3632,9 @@ test_multiple3 (const struct message *r1, const struct message *r2, const struct abort(); } - if (!message_eq(0, r1)) abort(); - if (message_count > 1 && !message_eq(1, r2)) abort(); - if (message_count > 2 && !message_eq(2, r3)) abort(); + if (!message_eq(0, 0, r1)) abort(); + if (message_count > 1 && !message_eq(1, 0, r2)) abort(); + if (message_count > 2 && !message_eq(2, 0, r3)) abort(); parser_free(); } @@ -3687,17 +3730,17 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess goto error; } - if (!message_eq(0, r1)) { + if (!message_eq(0, 0, r1)) { fprintf(stderr, "\n\nError matching messages[0] in test_scan.\n"); goto error; } - if (message_count > 1 && !message_eq(1, r2)) { + if (message_count > 1 && !message_eq(1, 0, r2)) { fprintf(stderr, "\n\nError matching messages[1] in test_scan.\n"); goto error; } - if (message_count > 2 && !message_eq(2, r3)) { + if (message_count > 2 && !message_eq(2, 0, r3)) { fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n"); goto error; } @@ -3796,7 +3839,29 @@ test_message_pause (const struct message *msg) abort(); } - if(!message_eq(0, msg)) abort(); + if(!message_eq(0, 0, msg)) abort(); + + parser_free(); +} + +/* Verify that body and next message won't be parsed in responses to CONNECT */ +void +test_message_connect (const struct message *msg) +{ + char *buf = (char*) msg->raw; + size_t buflen = strlen(msg->raw); + size_t nread; + + parser_init(msg->type); + + nread = parse_connect(buf, buflen); + + if (num_messages != 1) { + printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name); + abort(); + } + + if(!message_eq(0, 1, msg)) abort(); parser_free(); } @@ -3867,6 +3932,10 @@ main (void) test_message_pause(&responses[i]); } + for (i = 0; i < response_count; i++) { + test_message_connect(&responses[i]); + } + for (i = 0; i < response_count; i++) { if (!responses[i].should_keep_alive) continue; for (j = 0; j < response_count; j++) { From 9d4d529517e48ba6c066ee1a2b4079b734090920 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Tue, 19 Apr 2016 10:51:05 -0400 Subject: [PATCH 45/48] http: skip body and next message of CONNECT res When handling a response to `CONNECT` request - skip message body and do not attempt to parse the next message. `CONNECT` requests are used in similar sense to HTTP Upgrade. Fix: https://github.com/nodejs/node/pull/6198 PR-URL: https://github.com/nodejs/node/pull/6279 Reviewed-By: Brian White Reviewed-By: James M Snell --- lib/_http_client.js | 2 +- lib/_http_common.js | 7 +++++-- src/node_http_parser.cc | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/_http_client.js b/lib/_http_client.js index bc294263c7f..68eb125e0e1 100644 --- a/lib/_http_client.js +++ b/lib/_http_client.js @@ -432,7 +432,7 @@ function parserOnIncomingClient(res, shouldKeepAlive) { // Responses to CONNECT request is handled as Upgrade. if (req.method === 'CONNECT') { res.upgrade = true; - return true; // skip body + return 2; // skip body, and the rest } // Responses to HEAD requests are crazy. diff --git a/lib/_http_common.js b/lib/_http_common.js index 7c9fac5c6b7..583c5d610a5 100644 --- a/lib/_http_common.js +++ b/lib/_http_common.js @@ -96,7 +96,7 @@ function parserOnHeadersComplete(versionMajor, versionMinor, headers, method, parser.incoming.upgrade = upgrade; - var skipBody = false; // response to HEAD or CONNECT + var skipBody = 0; // response to HEAD or CONNECT if (!upgrade) { // For upgraded connections and CONNECT method request, we'll emit this @@ -105,7 +105,10 @@ function parserOnHeadersComplete(versionMajor, versionMinor, headers, method, skipBody = parser.onIncoming(parser.incoming, shouldKeepAlive); } - return skipBody; + if (typeof skipBody !== 'number') + return skipBody ? 1 : 0; + else + return skipBody; } // XXX This is a mess. diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index 7d30cfd99ee..d1a130d7eea 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -300,7 +300,7 @@ class Parser : public AsyncWrap { return -1; } - return head_response->IsTrue() ? 1 : 0; + return head_response->IntegerValue(); } From 0ecc430894f087e69518dc34e57d66cbae5a39d9 Mon Sep 17 00:00:00 2001 From: Josh Leder Date: Tue, 19 Apr 2016 10:50:20 -0400 Subject: [PATCH 46/48] test: add test for responses to HTTP CONNECT req See: https://github.com/nodejs/node/pull/6198 PR-URL: https://github.com/nodejs/node/pull/6279 Reviewed-By: Brian White Reviewed-By: James M Snell --- test/parallel/test-http-connect-req-res.js | 72 ++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 test/parallel/test-http-connect-req-res.js diff --git a/test/parallel/test-http-connect-req-res.js b/test/parallel/test-http-connect-req-res.js new file mode 100644 index 00000000000..bb5056fce49 --- /dev/null +++ b/test/parallel/test-http-connect-req-res.js @@ -0,0 +1,72 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const http = require('http'); + +const server = http.createServer(function(req, res) { + assert(false); +}); +server.on('connect', common.mustCall(function(req, socket, firstBodyChunk) { + assert.equal(req.method, 'CONNECT'); + assert.equal(req.url, 'example.com:443'); + console.error('Server got CONNECT request'); + + // It is legal for the server to send some data intended for the client + // along with the CONNECT response + socket.write( + 'HTTP/1.1 200 Connection established\r\n' + + 'Date: Tue, 15 Nov 1994 08:12:31 GMT\r\n' + + '\r\n' + + 'Head' + ); + + var data = firstBodyChunk.toString(); + socket.on('data', function(buf) { + data += buf.toString(); + }); + socket.on('end', function() { + socket.end(data); + }); +})); +server.listen(common.PORT, common.mustCall(function() { + const req = http.request({ + port: common.PORT, + method: 'CONNECT', + path: 'example.com:443' + }, function(res) { + assert(false); + }); + + req.on('close', common.mustCall(function() { })); + + req.on('connect', common.mustCall(function(res, socket, firstBodyChunk) { + console.error('Client got CONNECT request'); + + // Make sure this request got removed from the pool. + const name = 'localhost:' + common.PORT; + assert(!http.globalAgent.sockets.hasOwnProperty(name)); + assert(!http.globalAgent.requests.hasOwnProperty(name)); + + // Make sure this socket has detached. + assert(!socket.ondata); + assert(!socket.onend); + assert.equal(socket.listeners('connect').length, 0); + assert.equal(socket.listeners('data').length, 0); + + var data = firstBodyChunk.toString(); + + // test that the firstBodyChunk was not parsed as HTTP + assert.equal(data, 'Head'); + + socket.on('data', function(buf) { + data += buf.toString(); + }); + socket.on('end', function() { + assert.equal(data, 'HeadRequestEnd'); + server.close(); + }); + socket.end('End'); + })); + + req.end('Request'); +})); From 697790c1176bb4bb8062458c765fecc5e8a07646 Mon Sep 17 00:00:00 2001 From: Sakthipriyan Vairamani Date: Tue, 19 Apr 2016 19:14:50 +0530 Subject: [PATCH 47/48] src: fix -Wunused-result warning in e38bade This patch fixes the warning introduced by the changes in e38bade. Ref: https://github.com/nodejs/node/pull/6092 PR-URL: https://github.com/nodejs/node/pull/6276 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Brian White --- src/node.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/node.cc b/src/node.cc index dd427c792e9..c36161e7ff0 100644 --- a/src/node.cc +++ b/src/node.cc @@ -3229,7 +3229,8 @@ void SetupProcessObject(Environment* env, // pre-set _events object for faster emit checks Local events_obj = Object::New(env->isolate()); - events_obj->SetPrototype(env->context(), Null(env->isolate())); + maybe = events_obj->SetPrototype(env->context(), Null(env->isolate())); + CHECK(maybe.FromJust()); process->Set(env->events_string(), events_obj); } From 58c594ebf8e18671aadf3429315eb8ed12f27c7f Mon Sep 17 00:00:00 2001 From: Gibson Fahnestock Date: Mon, 11 Apr 2016 17:40:02 +0100 Subject: [PATCH 48/48] build: configuration changes to support s390/zLinux Since deps/v8 doesn't currently support s390/s390x, pick up deps/v8z instead. Based on afe84b856e2a2e2995693d37cae8372942c78ac0 modified: common.gypi modified: configure modified: lib/internal/v8_prof_processor.js modified: node.gyp --- common.gypi | 8 +++++- configure | 5 ++++ lib/internal/v8_prof_processor.js | 20 +++++++-------- node.gyp | 42 +++++++++++++++---------------- 4 files changed, 43 insertions(+), 32 deletions(-) diff --git a/common.gypi b/common.gypi index ac06e55b181..ab96102d6ab 100644 --- a/common.gypi +++ b/common.gypi @@ -36,10 +36,16 @@ ['GENERATOR == "ninja" or OS== "mac"', { 'OBJ_DIR': '<(PRODUCT_DIR)/obj', 'V8_BASE': '<(PRODUCT_DIR)/libv8_base.a', - }, { + }], + ['GENERATOR != "ninja" and OS!= "mac" and target_arch not in "s390 s390x"', { + 'OBJ_DIR': '<(PRODUCT_DIR)/obj.target', 'V8_BASE': '<(PRODUCT_DIR)/obj.target/deps/v8/tools/gyp/libv8_base.a', }], + ['GENERATOR != "ninja" and OS!= "mac" and target_arch in "s390 s390x"', { + 'OBJ_DIR': '<(PRODUCT_DIR)/obj.target', + 'V8_BASE': '<(PRODUCT_DIR)/obj.target/deps/v8z/tools/gyp/libv8_base.a', + }], ['openssl_fips != ""', { 'OPENSSL_PRODUCT': 'libcrypto.a', }, { diff --git a/configure b/configure index 03a889d04a4..4fc43ac4ebb 100755 --- a/configure +++ b/configure @@ -733,6 +733,11 @@ def configure_node(o): else: o['variables']['node_enable_v8_vtunejit'] = 'false' + if target_arch in ('s390', 's390x'): + o['variables']['v8_parent_path'] = 'deps/v8z' + else: + o['variables']['v8_parent_path'] = 'deps/v8' + if flavor in ('solaris', 'mac', 'linux', 'freebsd'): use_dtrace = not options.without_dtrace # Don't enable by default on linux and freebsd diff --git a/lib/internal/v8_prof_processor.js b/lib/internal/v8_prof_processor.js index c84b3104d20..1d62f6f39e1 100644 --- a/lib/internal/v8_prof_processor.js +++ b/lib/internal/v8_prof_processor.js @@ -1,15 +1,15 @@ const scriptFiles = [ 'internal/v8_prof_polyfill', - 'v8/tools/splaytree', - 'v8/tools/codemap', - 'v8/tools/csvparser', - 'v8/tools/consarray', - 'v8/tools/profile', - 'v8/tools/profile_view', - 'v8/tools/logreader', - 'v8/tools/tickprocessor', - 'v8/tools/SourceMap', - 'v8/tools/tickprocessor-driver' + v8_parent_path + '/tools/splaytree', + v8_parent_path + '/tools/codemap', + v8_parent_path + '/tools/csvparser', + v8_parent_path + '/tools/consarray', + v8_parent_path + '/tools/profile', + v8_parent_path + '/tools/profile_view', + v8_parent_path + '/tools/logreader', + v8_parent_path + '/tools/tickprocessor', + v8_parent_path + '/tools/SourceMap', + v8_parent_path + '/tools/tickprocessor-driver' ]; var script = ''; diff --git a/node.gyp b/node.gyp index 0e9fe40c419..518f27403a5 100644 --- a/node.gyp +++ b/node.gyp @@ -88,16 +88,16 @@ 'lib/internal/v8_prof_polyfill.js', 'lib/internal/v8_prof_processor.js', 'lib/internal/streams/lazy_transform.js', - 'deps/v8/tools/splaytree.js', - 'deps/v8/tools/codemap.js', - 'deps/v8/tools/consarray.js', - 'deps/v8/tools/csvparser.js', - 'deps/v8/tools/profile.js', - 'deps/v8/tools/profile_view.js', - 'deps/v8/tools/logreader.js', - 'deps/v8/tools/tickprocessor.js', - 'deps/v8/tools/SourceMap.js', - 'deps/v8/tools/tickprocessor-driver.js', + '<(v8_parent_path)/tools/splaytree.js', + '<(v8_parent_path)/tools/codemap.js', + '<(v8_parent_path)/tools/consarray.js', + '<(v8_parent_path)/tools/csvparser.js', + '<(v8_parent_path)/tools/profile.js', + '<(v8_parent_path)/tools/profile_view.js', + '<(v8_parent_path)/tools/logreader.js', + '<(v8_parent_path)/tools/tickprocessor.js', + '<(v8_parent_path)/tools/SourceMap.js', + '<(v8_parent_path)/tools/tickprocessor-driver.js', ], }, @@ -108,8 +108,8 @@ 'dependencies': [ 'node_js2c#host', - 'deps/v8/tools/gyp/v8.gyp:v8', - 'deps/v8/tools/gyp/v8.gyp:v8_libplatform' + '<(v8_parent_path)/tools/gyp/v8.gyp:v8', + '<(v8_parent_path)/tools/gyp/v8.gyp:v8_libplatform' ], 'include_dirs': [ @@ -117,7 +117,7 @@ 'tools/msvs/genfiles', 'deps/uv/src/ares', '<(SHARED_INTERMEDIATE_DIR)', # for node_natives.h - 'deps/v8' # include/v8_platform.h + '<(v8_parent_path)' # include/v8_platform.h ], 'sources': [ @@ -195,8 +195,8 @@ 'src/util.cc', 'src/string_search.cc', 'deps/http_parser/http_parser.h', - 'deps/v8/include/v8.h', - 'deps/v8/include/v8-debug.h', + '<(v8_parent_path)/include/v8.h', + '<(v8_parent_path)/include/v8-debug.h', '<(SHARED_INTERMEDIATE_DIR)/node_natives.h', # javascript files to make for an even more pleasant IDE experience '<@(library_files)', @@ -246,7 +246,7 @@ target_arch=="ia32" or target_arch=="x32")', { 'defines': [ 'NODE_ENABLE_VTUNE_PROFILING' ], 'dependencies': [ - 'deps/v8/src/third_party/vtune/v8vtune.gyp:v8_vtune' + '<(v8_parent_path)/src/third_party/vtune/v8vtune.gyp:v8_vtune' ], }], [ 'node_use_openssl=="true"', { @@ -371,7 +371,7 @@ 'defines': [ 'NODE_NO_BROWSER_GLOBALS' ], } ], [ 'v8_postmortem_support=="true"', { - 'dependencies': [ 'deps/v8/tools/gyp/v8.gyp:postmortem-metadata' ], + 'dependencies': [ '<(v8_parent_path)/tools/gyp/v8.gyp:postmortem-metadata' ], 'conditions': [ # -force_load is not applicable for the static library [ 'node_target_type!="static_library"', { @@ -690,12 +690,12 @@ 'type': 'executable', 'dependencies': [ 'deps/gtest/gtest.gyp:gtest', - 'deps/v8/tools/gyp/v8.gyp:v8', - 'deps/v8/tools/gyp/v8.gyp:v8_libplatform' + '<(v8_parent_path)/tools/gyp/v8.gyp:v8', + '<(v8_parent_path)/tools/gyp/v8.gyp:v8_libplatform' ], 'include_dirs': [ 'src', - 'deps/v8/include' + '<(v8_parent_path)/include' ], 'defines': [ # gtest's ASSERT macros conflict with our own. @@ -722,7 +722,7 @@ 'include_dirs': [ 'src', - 'deps/v8/include', + '<(v8_parent_path)/include', ], 'sources': [