From 46e773c5db9ebc106823594b82f4ff14a0a004f3 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 16 May 2017 15:15:14 +0200 Subject: [PATCH 01/12] src: check if --icu-data-dir= points to valid dir Call uc_init() after u_setDataDirectory() to find out if the data directory is actually valid. This commit removes parallel/test-intl-no-icu-data, added in commit 46345b9 ("src: make --icu-data-dir= switch testable"). It no longer works now that an invalid --icu-data-dir= argument is rejected. Coverage is now provided by parallel/test-icu-data-dir. Fixes: https://github.com/nodejs/node/issues/13043 Refs: https://github.com/nodejs/node-gyp/issues/1199 Reviewed-By: Colin Ihrig Reviewed-By: Refael Ackermann Reviewed-By: Steven R Loomis --- src/node.cc | 7 +++++-- src/node_i18n.cc | 7 ++++--- test/parallel/test-cli-node-options.js | 1 - test/parallel/test-icu-data-dir.js | 19 +++++++++++++++++++ test/parallel/test-intl-no-icu-data.js | 8 -------- 5 files changed, 28 insertions(+), 14 deletions(-) create mode 100644 test/parallel/test-icu-data-dir.js delete mode 100644 test/parallel/test-intl-no-icu-data.js diff --git a/src/node.cc b/src/node.cc index fb98fcebc2a..8827195570f 100644 --- a/src/node.cc +++ b/src/node.cc @@ -4342,8 +4342,11 @@ void Init(int* argc, // Initialize ICU. // If icu_data_dir is empty here, it will load the 'minimal' data. if (!i18n::InitializeICUDirectory(icu_data_dir)) { - FatalError(nullptr, "Could not initialize ICU " - "(check NODE_ICU_DATA or --icu-data-dir parameters)"); + fprintf(stderr, + "%s: could not initialize ICU " + "(check NODE_ICU_DATA or --icu-data-dir parameters)", + argv[0]); + exit(9); } #endif diff --git a/src/node_i18n.cc b/src/node_i18n.cc index 6d966bb117d..30394f3a47b 100644 --- a/src/node_i18n.cc +++ b/src/node_i18n.cc @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -418,19 +419,19 @@ void GetVersion(const FunctionCallbackInfo& args) { } // anonymous namespace bool InitializeICUDirectory(const std::string& path) { + UErrorCode status = U_ZERO_ERROR; if (path.empty()) { - UErrorCode status = U_ZERO_ERROR; #ifdef NODE_HAVE_SMALL_ICU // install the 'small' data. udata_setCommonData(&SMALL_ICUDATA_ENTRY_POINT, &status); #else // !NODE_HAVE_SMALL_ICU // no small data, so nothing to do. #endif // !NODE_HAVE_SMALL_ICU - return (status == U_ZERO_ERROR); } else { u_setDataDirectory(path.c_str()); - return true; // No error. + u_init(&status); } + return status == U_ZERO_ERROR; } int32_t ToUnicode(MaybeStackBuffer* buf, diff --git a/test/parallel/test-cli-node-options.js b/test/parallel/test-cli-node-options.js index 6b0b9f53f9a..bff04718089 100644 --- a/test/parallel/test-cli-node-options.js +++ b/test/parallel/test-cli-node-options.js @@ -57,7 +57,6 @@ if (common.hasCrypto) { expect('--use-bundled-ca', 'B\n'); expect('--openssl-config=_ossl_cfg', 'B\n'); } -expect('--icu-data-dir=_d', 'B\n'); // V8 options expect('--max_old_space_size=0', 'B\n'); diff --git a/test/parallel/test-icu-data-dir.js b/test/parallel/test-icu-data-dir.js new file mode 100644 index 00000000000..07a4391505b --- /dev/null +++ b/test/parallel/test-icu-data-dir.js @@ -0,0 +1,19 @@ +'use strict'; +require('../common'); +const assert = require('assert'); +const { spawnSync } = require('child_process'); + +const expected = + 'could not initialize ICU ' + + '(check NODE_ICU_DATA or --icu-data-dir parameters)'; + +{ + const child = spawnSync(process.execPath, ['--icu-data-dir=/', '-e', '0']); + assert(child.stderr.toString().includes(expected)); +} + +{ + const env = { NODE_ICU_DATA: '/' }; + const child = spawnSync(process.execPath, ['-e', '0'], { env }); + assert(child.stderr.toString().includes(expected)); +} diff --git a/test/parallel/test-intl-no-icu-data.js b/test/parallel/test-intl-no-icu-data.js deleted file mode 100644 index 695a4698b56..00000000000 --- a/test/parallel/test-intl-no-icu-data.js +++ /dev/null @@ -1,8 +0,0 @@ -// Flags: --icu-data-dir=test/fixtures/empty/ -'use strict'; -require('../common'); -const assert = require('assert'); -const config = process.binding('config'); - -assert.deepStrictEqual(Intl.NumberFormat.supportedLocalesOf('en'), []); -assert.strictEqual(config.icuDataDir, 'test/fixtures/empty/'); From fccc0bf6e68981f6225315875524e1a0b56fcc20 Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Tue, 9 May 2017 17:16:52 -0400 Subject: [PATCH 02/12] test: add mustCallAtLeast PR-URL: https://github.com/nodejs/node/pull/12935 Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- test/common/README.md | 17 +++++++++--- test/common/index.js | 35 +++++++++++++++++-------- test/fixtures/failmustcall1.js | 3 +++ test/fixtures/failmustcall2.js | 3 +++ test/parallel/test-common.js | 47 +++++++++++++++++++++++++++++++--- 5 files changed, 88 insertions(+), 17 deletions(-) create mode 100644 test/fixtures/failmustcall1.js create mode 100644 test/fixtures/failmustcall2.js diff --git a/test/common/README.md b/test/common/README.md index 267d28140c5..492b5acdea5 100644 --- a/test/common/README.md +++ b/test/common/README.md @@ -182,9 +182,9 @@ Gets IP of localhost Array of IPV6 hosts. -### mustCall([fn][, expected]) -* fn [<Function>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) -* expected [<Number>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type) default = 1 +### mustCall([fn][, exact]) +* `fn` [<Function>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) default = `common.noop` +* `exact` [<Number>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type) default = 1 * return [<Function>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) Returns a function that calls `fn`. If the returned function has not been called @@ -193,6 +193,17 @@ fail. If `fn` is not provided, `common.noop` will be used. +### mustCallAtLeast([fn][, minimum]) +* `fn` [<Function>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) default = `common.noop` +* `minimum` [<Number>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type) default = 1 +* return [<Function>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) + +Returns a function that calls `fn`. If the returned function has not been called +at least `minimum` number of times when the test is complete, then the test will +fail. + +If `fn` is not provided, `common.noop` will be used. + ### nodeProcessAborted(exitCode, signal) * `exitCode` [<Number>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type) * `signal` [<String>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type) diff --git a/test/common/index.js b/test/common/index.js index cb8d333a289..d657e36f06c 100644 --- a/test/common/index.js +++ b/test/common/index.js @@ -459,13 +459,19 @@ function runCallChecks(exitCode) { if (exitCode !== 0) return; const failed = mustCallChecks.filter(function(context) { - return context.actual !== context.expected; + if ('minimum' in context) { + context.messageSegment = `at least ${context.minimum}`; + return context.actual < context.minimum; + } else { + context.messageSegment = `exactly ${context.exact}`; + return context.actual !== context.exact; + } }); failed.forEach(function(context) { - console.log('Mismatched %s function calls. Expected %d, actual %d.', + console.log('Mismatched %s function calls. Expected %s, actual %d.', context.name, - context.expected, + context.messageSegment, context.actual); console.log(context.stack.split('\n').slice(2).join('\n')); }); @@ -473,22 +479,29 @@ function runCallChecks(exitCode) { if (failed.length) process.exit(1); } +exports.mustCall = function(fn, exact) { + return _mustCallInner(fn, exact, 'exact'); +}; -exports.mustCall = function(fn, expected) { +exports.mustCallAtLeast = function(fn, minimum) { + return _mustCallInner(fn, minimum, 'minimum'); +}; + +function _mustCallInner(fn, criteria, field) { if (typeof fn === 'number') { - expected = fn; + criteria = fn; fn = noop; } else if (fn === undefined) { fn = noop; } - if (expected === undefined) - expected = 1; - else if (typeof expected !== 'number') - throw new TypeError(`Invalid expected value: ${expected}`); + if (criteria === undefined) + criteria = 1; + else if (typeof criteria !== 'number') + throw new TypeError(`Invalid ${field} value: ${criteria}`); const context = { - expected: expected, + [field]: criteria, actual: 0, stack: (new Error()).stack, name: fn.name || '' @@ -503,7 +516,7 @@ exports.mustCall = function(fn, expected) { context.actual++; return fn.apply(this, arguments); }; -}; +} exports.hasMultiLocalhost = function hasMultiLocalhost() { const TCP = process.binding('tcp_wrap').TCP; diff --git a/test/fixtures/failmustcall1.js b/test/fixtures/failmustcall1.js new file mode 100644 index 00000000000..a54740eb296 --- /dev/null +++ b/test/fixtures/failmustcall1.js @@ -0,0 +1,3 @@ +const common = require('../common'); +const f = common.mustCall( () => {}, 2); +f(); diff --git a/test/fixtures/failmustcall2.js b/test/fixtures/failmustcall2.js new file mode 100644 index 00000000000..89f8d23922e --- /dev/null +++ b/test/fixtures/failmustcall2.js @@ -0,0 +1,3 @@ +const common = require('../common'); +const f = common.mustCallAtLeast(() => {}, 2); +f(); diff --git a/test/parallel/test-common.js b/test/parallel/test-common.js index 2bda20acd94..0a4e1d72f0f 100644 --- a/test/parallel/test-common.js +++ b/test/parallel/test-common.js @@ -22,7 +22,8 @@ 'use strict'; const common = require('../common'); const assert = require('assert'); - +const {join} = require('path'); +const {execFile} = require('child_process'); // test for leaked global detection global.gc = 42; // Not a valid global unless --expose_gc is set. @@ -33,12 +34,15 @@ delete global.gc; // common.mustCall() tests assert.throws(function() { common.mustCall(function() {}, 'foo'); -}, /^TypeError: Invalid expected value: foo$/); +}, /^TypeError: Invalid exact value: foo$/); assert.throws(function() { common.mustCall(function() {}, /foo/); -}, /^TypeError: Invalid expected value: \/foo\/$/); +}, /^TypeError: Invalid exact value: \/foo\/$/); +assert.throws(function() { + common.mustCallAtLeast(function() {}, /foo/); +}, /^TypeError: Invalid minimum value: \/foo\/$/); // assert.fail() tests assert.throws( @@ -47,3 +51,40 @@ assert.throws( code: 'ERR_ASSERTION', message: /^fhqwhgads$/ })); + +const fnOnce = common.mustCall(() => {}); +fnOnce(); +const fnTwice = common.mustCall(() => {}, 2); +fnTwice(); +fnTwice(); +const fnAtLeast1Called1 = common.mustCallAtLeast(() => {}, 1); +fnAtLeast1Called1(); +const fnAtLeast1Called2 = common.mustCallAtLeast(() => {}, 1); +fnAtLeast1Called2(); +fnAtLeast1Called2(); +const fnAtLeast2Called2 = common.mustCallAtLeast(() => {}, 2); +fnAtLeast2Called2(); +fnAtLeast2Called2(); +const fnAtLeast2Called3 = common.mustCallAtLeast(() => {}, 2); +fnAtLeast2Called3(); +fnAtLeast2Called3(); +fnAtLeast2Called3(); + +const failFixtures = [ + [ + join(common.fixturesDir, 'failmustcall1.js'), + 'Mismatched function calls. Expected exactly 2, actual 1.' + ], [ + join(common.fixturesDir, 'failmustcall2.js'), + 'Mismatched function calls. Expected at least 2, actual 1.' + ] +]; +for (const p of failFixtures) { + const [file, expected] = p; + execFile(process.argv[0], [file], common.mustCall((ex, stdout, stderr) => { + assert.ok(ex); + assert.strictEqual(stderr, ''); + const firstLine = stdout.split('\n').shift(); + assert.strictEqual(firstLine, expected); + })); +} From 3702ae732eadd9d7c64681edcdd76cd7a30f6381 Mon Sep 17 00:00:00 2001 From: Michael Dawson Date: Wed, 17 May 2017 17:46:47 -0400 Subject: [PATCH 03/12] doc: add additional useful ci job to list PR-URL: https://github.com/nodejs/node/pull/13086 Reviewed-By: Gibson Fahnestock Reviewed-By: Luigi Pinca Reviewed-By: Richard Lau --- COLLABORATOR_GUIDE.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/COLLABORATOR_GUIDE.md b/COLLABORATOR_GUIDE.md index 157925f8df8..116624a79ae 100644 --- a/COLLABORATOR_GUIDE.md +++ b/COLLABORATOR_GUIDE.md @@ -108,6 +108,10 @@ you can run [`citgm-abi-smoker`](https://ci.nodejs.org/job/citgm-abi-smoker/). is designed to allow one to run a group of tests over and over on a specific platform to confirm that the test is reliable. +* [`node-test-commit-v8-linux`](https://ci.nodejs.org/job/node-test-commit-v8-linux/) +is designed to allow validation of changes to the copy of V8 in the Node.js +tree by running the standard V8 tests. It should be run whenever the +level of V8 within Node.js is updated or new patches are floated on V8. ### Internal vs. Public API From a63b245b0a0d15e9a494b3a4602031bfc6a51ff8 Mon Sep 17 00:00:00 2001 From: Jason Ginchereau Date: Wed, 17 May 2017 16:56:37 -0700 Subject: [PATCH 04/12] n-api: Retain last code when getting error info Unlike most N-API functions, `napi_get_last_error_info()` should not clear the last error code when successful, because a pointer to (not a copy of) the error info structure is returned via an out parameter. PR-URL: https://github.com/nodejs/node/pull/13087 Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: Michael Dawson --- src/node_api.cc | 2 +- test/addons-napi/test_napi_status/test_napi_status.cc | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/node_api.cc b/src/node_api.cc index 3a65862991c..d0e535dca06 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -755,7 +755,7 @@ napi_status napi_get_last_error_info(napi_env env, error_messages[env->last_error.error_code]; *result = &(env->last_error); - return napi_clear_last_error(env); + return napi_ok; } napi_status napi_create_function(napi_env env, diff --git a/test/addons-napi/test_napi_status/test_napi_status.cc b/test/addons-napi/test_napi_status/test_napi_status.cc index 9046feffd4a..9e340aa46e1 100644 --- a/test/addons-napi/test_napi_status/test_napi_status.cc +++ b/test/addons-napi/test_napi_status/test_napi_status.cc @@ -10,6 +10,14 @@ napi_value createNapiError(napi_env env, napi_callback_info info) { NAPI_ASSERT(env, status != napi_ok, "Failed to produce error condition"); + const napi_extended_error_info *error_info = 0; + NAPI_CALL(env, napi_get_last_error_info(env, &error_info)); + + NAPI_ASSERT(env, error_info->error_code == status, + "Last error info code should match last status"); + NAPI_ASSERT(env, error_info->error_message, + "Last error info message should not be null"); + return nullptr; } From 4a7b7e8097fcd43bd1823050607270530d05541b Mon Sep 17 00:00:00 2001 From: Michael Dawson Date: Wed, 17 May 2017 17:16:37 -0400 Subject: [PATCH 05/12] doc: add reference to node_api.h in docs Realized that we don't actually point people to the file to include in order to access N-API functions. Add that. PR-URL: https://github.com/nodejs/node/pull/13084 Reviewed-By: Colin Ihrig Reviewed-By: Gibson Fahnestock Reviewed-By: Luigi Pinca Reviewed-By: Anna Henningsen --- doc/api/n-api.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 423e71859de..de841331aba 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -52,6 +52,14 @@ for the N-API C based functions exported by Node.js. These wrappers are not part of N-API, nor will they be maintained as part of Node.js. One such example is: [node-api](https://github.com/nodejs/node-api). +In order to use the N-API functions, include the file +[node_api.h](https://github.com/nodejs/node/blob/master/src/node_api.h) +which is located in the src directory in the node development tree. +For example: +```C +#include +``` + ## Basic N-API Data Types N-API exposes the following fundamental datatypes as abstractions that are From 6bfdeedce5529810dbe7c61bd712fc50174a19f1 Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Thu, 18 May 2017 00:43:09 -0400 Subject: [PATCH 06/12] async_wrap: add `asyncReset` to `TLSWrap` When using an Agent for HTTPS, `TLSSocket`s are reused and need to have the ability to `asyncReset` from JS. PR-URL: https://github.com/nodejs/node/pull/13092 Fixes: https://github.com/nodejs/node/issues/13045 Reviewed-By: Andreas Madsen Reviewed-By: Colin Ihrig Reviewed-By: Matteo Collina --- src/tls_wrap.cc | 1 + test/parallel/test-async-wrap-GH13045.js | 53 ++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 test/parallel/test-async-wrap-GH13045.js diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc index 05349b2f552..e6de9423710 100644 --- a/src/tls_wrap.cc +++ b/src/tls_wrap.cc @@ -940,6 +940,7 @@ void TLSWrap::Initialize(Local target, t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "TLSWrap")); env->SetProtoMethod(t, "getAsyncId", AsyncWrap::GetAsyncId); + env->SetProtoMethod(t, "asyncReset", AsyncWrap::AsyncReset); env->SetProtoMethod(t, "receive", Receive); env->SetProtoMethod(t, "start", Start); env->SetProtoMethod(t, "setVerifyMode", SetVerifyMode); diff --git a/test/parallel/test-async-wrap-GH13045.js b/test/parallel/test-async-wrap-GH13045.js new file mode 100644 index 00000000000..9fab1ee2ae1 --- /dev/null +++ b/test/parallel/test-async-wrap-GH13045.js @@ -0,0 +1,53 @@ +'use strict'; +const common = require('../common'); + +// Refs: https://github.com/nodejs/node/issues/13045 +// An HTTP Agent reuses a TLSSocket, and makes a failed call to `asyncReset`. + +const assert = require('assert'); +const https = require('https'); +const fs = require('fs'); + +const serverOptions = { + key: fs.readFileSync(`${common.fixturesDir}/keys/agent1-key.pem`), + cert: fs.readFileSync(`${common.fixturesDir}/keys/agent1-cert.pem`), + ca: fs.readFileSync(`${common.fixturesDir}/keys/ca1-cert.pem`) +}; + +const server = https.createServer(serverOptions, common.mustCall((req, res) => { + res.end('hello world\n'); +}, 2)); + +server.listen(0, common.mustCall(function() { + const port = this.address().port; + const clientOptions = { + agent: new https.Agent({ + keepAlive: true, + rejectUnauthorized: false + }), + port: port + }; + + const req = https.get(clientOptions, common.mustCall((res) => { + assert.strictEqual(res.statusCode, 200); + res.on('error', (err) => assert.fail(err)); + res.socket.on('error', (err) => assert.fail(err)); + res.resume(); + // drain the socket and wait for it to be free to reuse + res.socket.once('free', () => { + // This is the pain point. Internally the Agent will call + // `socket._handle.asyncReset()` and if the _handle does not implement + // `asyncReset` this will throw TypeError + const req2 = https.get(clientOptions, common.mustCall((res2) => { + assert.strictEqual(res.statusCode, 200); + res2.on('error', (err) => assert.fail(err)); + res2.socket.on('error', (err) => assert.fail(err)); + // this should be the end of the test + res2.destroy(); + server.close(); + })); + req2.on('error', (err) => assert.fail(err)); + }); + })); + req.on('error', (err) => assert.fail(err)); +})); From 658741b9d9255c5e18fafa76f3a70876153c8d59 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sun, 14 May 2017 20:39:36 -0700 Subject: [PATCH 07/12] test: refactor test-https-set-timeout-server * Add common.mustCall() for error handlers. * Alphabetize modules PR-URL: https://github.com/nodejs/node/pull/13032 Reviewed-By: Luigi Pinca Reviewed-By: Colin Ihrig Reviewed-By: Refael Ackermann Reviewed-By: James M Snell Reviewed-By: Alexey Orlenko --- test/sequential/test-https-set-timeout-server.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/sequential/test-https-set-timeout-server.js b/test/sequential/test-https-set-timeout-server.js index 92619b5b826..100354b54bf 100644 --- a/test/sequential/test-https-set-timeout-server.js +++ b/test/sequential/test-https-set-timeout-server.js @@ -21,16 +21,16 @@ 'use strict'; const common = require('../common'); -const assert = require('assert'); if (!common.hasCrypto) { common.skip('missing crypto'); return; } -const https = require('https'); -const tls = require('tls'); +const assert = require('assert'); const fs = require('fs'); +const https = require('https'); +const tls = require('tls'); const tests = []; @@ -69,7 +69,7 @@ test(function serverTimeout(cb) { https.get({ port: this.address().port, rejectUnauthorized: false - }).on('error', common.noop); + }).on('error', common.mustCall()); })); }); @@ -90,7 +90,7 @@ test(function serverRequestTimeout(cb) { method: 'POST', rejectUnauthorized: false }); - req.on('error', common.noop); + req.on('error', common.mustCall()); req.write('Hello'); // req is in progress }); @@ -111,7 +111,7 @@ test(function serverResponseTimeout(cb) { https.get({ port: this.address().port, rejectUnauthorized: false - }).on('error', common.noop); + }).on('error', common.mustCall()); }); }); @@ -131,7 +131,7 @@ test(function serverRequestNotTimeoutAfterEnd(cb) { https.get({ port: this.address().port, rejectUnauthorized: false - }).on('error', common.noop); + }).on('error', common.mustCall()); }); }); From 525497596a51ef2e6653b930ca525046d27c9fd5 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sun, 14 May 2017 12:42:37 -0700 Subject: [PATCH 08/12] test: refactor test-net-GH-5504 * Improve comments describing test. * Remove unnecessary `common.noop` * Remove confusing scoping of `c` identifier PR-URL: https://github.com/nodejs/node/pull/13025 Reviewed-By: Refael Ackermann Reviewed-By: Luigi Pinca Reviewed-By: Gibson Fahnestock Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- test/sequential/test-net-GH-5504.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/test/sequential/test-net-GH-5504.js b/test/sequential/test-net-GH-5504.js index 0c4d9bc6940..d744525710d 100644 --- a/test/sequential/test-net-GH-5504.js +++ b/test/sequential/test-net-GH-5504.js @@ -22,11 +22,13 @@ 'use strict'; const common = require('../common'); -// this test only fails with CentOS 6.3 using kernel version 2.6.32 -// On other linuxes and darwin, the `read` call gets an ECONNRESET in +// Ref: https://github.com/nodejs/node-v0.x-archive/issues/5504 +// +// This test only fails with CentOS 6.3 using kernel version 2.6.32. +// On other Linuxes and macOS, the `read` call gets an ECONNRESET in // that case. On sunos, the `write` call fails with EPIPE. // -// However, old CentOS will occasionally send an EOF instead of a +// However, old CentOS will occasionally send an EOF instead of an // ECONNRESET or EPIPE when the client has been destroyed abruptly. // // Make sure we don't keep trying to write or read more in that case. @@ -74,25 +76,24 @@ function parent() { NODE_DEBUG: 'net' }) }); - let c; wrap(s.stderr, process.stderr, 'SERVER 2>'); wrap(s.stdout, process.stdout, 'SERVER 1>'); - s.on('exit', common.mustCall(common.noop)); + s.on('exit', common.mustCall()); s.stdout.once('data', common.mustCall(function() { - c = spawn(node, [__filename, 'client']); + const c = spawn(node, [__filename, 'client']); wrap(c.stderr, process.stderr, 'CLIENT 2>'); wrap(c.stdout, process.stdout, 'CLIENT 1>'); - c.on('exit', common.mustCall(common.noop)); + c.on('exit', common.mustCall()); })); function wrap(inp, out, w) { inp.setEncoding('utf8'); - inp.on('data', function(c) { - c = c.trim(); - if (!c) return; - out.write(`${w}${c.split('\n').join(`\n${w}`)}\n`); + inp.on('data', function(chunk) { + chunk = chunk.trim(); + if (!chunk) return; + out.write(`${w}${chunk.split('\n').join(`\n${w}`)}\n`); }); } } From 841bb4c61f07a5c2bf818a3b985ea0f88257210e Mon Sep 17 00:00:00 2001 From: Timothy Gu Date: Thu, 4 May 2017 23:43:47 -0700 Subject: [PATCH 09/12] url: fix C0 control and whitespace handling PR-URL: https://github.com/nodejs/node/pull/12846 Fixes: https://github.com/nodejs/node/issues/12825 Refs: https://github.com/w3c/web-platform-tests/pull/5792 Reviewed-By: James M Snell Reviewed-By: Joyee Cheung --- src/node_url.cc | 59 +++++++++++++++++++++++++------------- src/node_url.h | 17 +++++++---- test/fixtures/url-tests.js | 32 ++++++++++++++++++++- 3 files changed, 81 insertions(+), 27 deletions(-) diff --git a/src/node_url.cc b/src/node_url.cc index 2bdc080953f..703ff4ffd61 100644 --- a/src/node_url.cc +++ b/src/node_url.cc @@ -133,6 +133,9 @@ enum url_error_cb_args { // https://infra.spec.whatwg.org/#ascii-tab-or-newline CHAR_TEST(8, IsASCIITabOrNewline, (ch == '\t' || ch == '\n' || ch == '\r')) +// https://infra.spec.whatwg.org/#c0-control-or-space +CHAR_TEST(8, IsC0ControlOrSpace, (ch >= '\0' && ch <= ' ')) + // https://infra.spec.whatwg.org/#ascii-digit CHAR_TEST(8, IsASCIIDigit, (ch >= '0' && ch <= '9')) @@ -1134,15 +1137,45 @@ static inline void ShortenUrlPath(struct url_data* url) { } void URL::Parse(const char* input, - const size_t len, + size_t len, enum url_parse_state state_override, struct url_data* url, + bool has_url, const struct url_data* base, bool has_base) { + const char* p = input; + const char* end = input + len; + + if (!has_url) { + for (const char* ptr = p; ptr < end; ptr++) { + if (IsC0ControlOrSpace(*ptr)) + p++; + else + break; + } + for (const char* ptr = end - 1; ptr >= p; ptr--) { + if (IsC0ControlOrSpace(*ptr)) + end--; + else + break; + } + len = end - p; + } + + std::string whitespace_stripped; + whitespace_stripped.reserve(len); + for (const char* ptr = p; ptr < end; ptr++) + if (!IsASCIITabOrNewline(*ptr)) + whitespace_stripped += *ptr; + + input = whitespace_stripped.c_str(); + len = whitespace_stripped.size(); + p = input; + end = input + len; + bool atflag = false; bool sbflag = false; bool uflag = false; - int wskip = 0; std::string buffer; url->scheme.reserve(len); @@ -1159,9 +1192,6 @@ void URL::Parse(const char* input, enum url_parse_state state = has_state_override ? state_override : kSchemeStart; - const char* p = input; - const char* end = input + len; - if (state < kSchemeStart || state > kFragment) { url->flags |= URL_FLAGS_INVALID_PARSE_STATE; return; @@ -1171,18 +1201,6 @@ void URL::Parse(const char* input, const char ch = p < end ? p[0] : kEOL; const size_t remaining = end == p ? 0 : (end - p - 1); - if (IsASCIITabOrNewline(ch)) { - if (state == kAuthority) { - // It's necessary to keep track of how much whitespace - // is being ignored when in kAuthority state because of - // how the buffer is managed. TODO: See if there's a better - // way - wskip++; - } - p++; - continue; - } - bool special = (url->flags & URL_FLAGS_SPECIAL); bool cannot_be_base; const bool special_back_slash = (special && ch == '\\'); @@ -1500,7 +1518,7 @@ void URL::Parse(const char* input, url->flags |= URL_FLAGS_FAILED; return; } - p -= buffer.size() + 1 + wskip; + p -= buffer.size() + 1; buffer.clear(); state = kHost; } else { @@ -1892,16 +1910,17 @@ static void Parse(Environment* env, HandleScope handle_scope(isolate); Context::Scope context_scope(context); + const bool has_context = context_obj->IsObject(); const bool has_base = base_obj->IsObject(); struct url_data base; struct url_data url; - if (context_obj->IsObject()) + if (has_context) HarvestContext(env, &url, context_obj.As()); if (has_base) HarvestBase(env, &base, base_obj.As()); - URL::Parse(input, len, state_override, &url, &base, has_base); + URL::Parse(input, len, state_override, &url, has_context, &base, has_base); if ((url.flags & URL_FLAGS_INVALID_PARSE_STATE) || ((state_override != kUnknownState) && (url.flags & URL_FLAGS_TERMINATED))) diff --git a/src/node_url.h b/src/node_url.h index 49bfb264e8d..72ac366ec13 100644 --- a/src/node_url.h +++ b/src/node_url.h @@ -81,30 +81,35 @@ struct url_data { class URL { public: static void Parse(const char* input, - const size_t len, + size_t len, enum url_parse_state state_override, struct url_data* url, + bool has_url, const struct url_data* base, bool has_base); URL(const char* input, const size_t len) { - Parse(input, len, kUnknownState, &context_, nullptr, false); + Parse(input, len, kUnknownState, &context_, false, nullptr, false); } URL(const char* input, const size_t len, const URL* base) { if (base != nullptr) - Parse(input, len, kUnknownState, &context_, &(base->context_), true); + Parse(input, len, kUnknownState, + &context_, false, + &(base->context_), true); else - Parse(input, len, kUnknownState, &context_, nullptr, false); + Parse(input, len, kUnknownState, &context_, false, nullptr, false); } URL(const char* input, const size_t len, const char* base, const size_t baselen) { if (base != nullptr && baselen > 0) { URL _base(base, baselen); - Parse(input, len, kUnknownState, &context_, &(_base.context_), true); + Parse(input, len, kUnknownState, + &context_, false, + &(_base.context_), true); } else { - Parse(input, len, kUnknownState, &context_, nullptr, false); + Parse(input, len, kUnknownState, &context_, false, nullptr, false); } } diff --git a/test/fixtures/url-tests.js b/test/fixtures/url-tests.js index befe325f931..f75ea129906 100644 --- a/test/fixtures/url-tests.js +++ b/test/fixtures/url-tests.js @@ -1,7 +1,7 @@ 'use strict'; /* WPT Refs: - https://github.com/w3c/web-platform-tests/blob/28541bb/url/urltestdata.json + https://github.com/w3c/web-platform-tests/blob/0f26c418a5/url/urltestdata.json License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html */ module.exports = @@ -3566,6 +3566,22 @@ module.exports = "search": "", "hash": "" }, + "Leading and trailing C0 control or space", + { + "input": "\u0000\u001b\u0004\u0012 http://example.com/\u001f \u000d ", + "base": "about:blank", + "href": "http://example.com/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, "Ideographic full stop (full-width period for Chinese, etc.) should be treated as a dot. U+3002 is mapped to U+002E (dot)", { "input": "http://www.foo。bar.com", @@ -5487,6 +5503,20 @@ module.exports = "search": "", "hash": "" }, + { + "input": "C|\n/", + "base": "file://host/dir/file", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, { "input": "C|\\", "base": "file://host/dir/file", From 06a617aa21c434b5e607370e7ee0051d506a4793 Mon Sep 17 00:00:00 2001 From: Rajaram Gaunker Date: Thu, 11 May 2017 00:19:15 -0700 Subject: [PATCH 10/12] url: update IDNA error conditions This commit contains three separate changes: - Always return a string from ToUnicode no matter if an error occurred. - Disable CheckHyphens boolean flag. This flag will soon be enabled in the URL Standard, but is implemented manually by selectively ignoring certain errors. - Enable CheckBidi boolean flag per URL Standard update. This allows domain names with hyphens at 3 and 4th position, as well as those with leading and trailing hyphens. They are technically invalid, but seen in the wild. Tests are updated and simplified accordingly. PR-URL: https://github.com/nodejs/node/pull/12966 Fixes: https://github.com/nodejs/node/issues/12965 Refs: https://github.com/whatwg/url/pull/309 Reviewed-By: Daijiro Wachi Reviewed-By: Timothy Gu --- src/node_i18n.cc | 38 +++++++++++-------- src/node_i18n.h | 3 +- test/fixtures/url-idna.js | 33 ++++++++++------ test/parallel/test-icu-punycode.js | 22 ++++------- .../parallel/test-url-domain-ascii-unicode.js | 3 +- test/parallel/test-whatwg-url-domainto.js | 11 ++---- 6 files changed, 59 insertions(+), 51 deletions(-) diff --git a/src/node_i18n.cc b/src/node_i18n.cc index 30394f3a47b..98818b581b7 100644 --- a/src/node_i18n.cc +++ b/src/node_i18n.cc @@ -436,11 +436,9 @@ bool InitializeICUDirectory(const std::string& path) { int32_t ToUnicode(MaybeStackBuffer* buf, const char* input, - size_t length, - bool lenient) { + size_t length) { UErrorCode status = U_ZERO_ERROR; - uint32_t options = UIDNA_DEFAULT; - options |= UIDNA_NONTRANSITIONAL_TO_UNICODE; + uint32_t options = UIDNA_NONTRANSITIONAL_TO_UNICODE; UIDNA* uidna = uidna_openUTS46(options, &status); if (U_FAILURE(status)) return -1; @@ -462,14 +460,10 @@ int32_t ToUnicode(MaybeStackBuffer* buf, &status); } - // UTS #46's ToUnicode operation applies no validation of domain name length - // (nor a flag requesting it to do so, like VerifyDnsLength for ToASCII). For - // that reason, unlike ToASCII below, ICU4C correctly accepts long domain - // names. However, ICU4C still sets the EMPTY_LABEL error in contrary to UTS - // #46. Therefore, explicitly filters out that error here. - info.errors &= ~UIDNA_ERROR_EMPTY_LABEL; + // info.errors is ignored as UTS #46 ToUnicode always produces a Unicode + // string, regardless of whether an error occurred. - if (U_FAILURE(status) || (!lenient && info.errors != 0)) { + if (U_FAILURE(status)) { len = -1; buf->SetLength(0); } else { @@ -485,8 +479,7 @@ int32_t ToASCII(MaybeStackBuffer* buf, size_t length, bool lenient) { UErrorCode status = U_ZERO_ERROR; - uint32_t options = UIDNA_DEFAULT; - options |= UIDNA_NONTRANSITIONAL_TO_ASCII; + uint32_t options = UIDNA_NONTRANSITIONAL_TO_ASCII | UIDNA_CHECK_BIDI; UIDNA* uidna = uidna_openUTS46(options, &status); if (U_FAILURE(status)) return -1; @@ -518,6 +511,21 @@ int32_t ToASCII(MaybeStackBuffer* buf, info.errors &= ~UIDNA_ERROR_LABEL_TOO_LONG; info.errors &= ~UIDNA_ERROR_DOMAIN_NAME_TOO_LONG; + // These error conditions are mandated unconditionally by UTS #46 version + // 9.0.0 (rev. 17), but were found to be incompatible with actual domain + // names in the wild. As such, in the current UTS #46 draft (rev. 18) these + // checks are made optional depending on the CheckHyphens flag, which will be + // disabled in WHATWG URL's "domain to ASCII" algorithm soon. + // Refs: + // - https://github.com/whatwg/url/issues/53 + // - https://github.com/whatwg/url/pull/309 + // - http://www.unicode.org/review/pri317/ + // - http://www.unicode.org/reports/tr46/tr46-18.html + // - https://www.icann.org/news/announcement-2000-01-07-en + info.errors &= ~UIDNA_ERROR_HYPHEN_3_4; + info.errors &= ~UIDNA_ERROR_LEADING_HYPHEN; + info.errors &= ~UIDNA_ERROR_TRAILING_HYPHEN; + if (U_FAILURE(status) || (!lenient && info.errors != 0)) { len = -1; buf->SetLength(0); @@ -534,11 +542,9 @@ static void ToUnicode(const FunctionCallbackInfo& args) { CHECK_GE(args.Length(), 1); CHECK(args[0]->IsString()); Utf8Value val(env->isolate(), args[0]); - // optional arg - bool lenient = args[1]->BooleanValue(env->context()).FromJust(); MaybeStackBuffer buf; - int32_t len = ToUnicode(&buf, *val, val.length(), lenient); + int32_t len = ToUnicode(&buf, *val, val.length()); if (len < 0) { return env->ThrowError("Cannot convert name to Unicode"); diff --git a/src/node_i18n.h b/src/node_i18n.h index 78e18fdb370..cc1f3e6ea53 100644 --- a/src/node_i18n.h +++ b/src/node_i18n.h @@ -43,8 +43,7 @@ int32_t ToASCII(MaybeStackBuffer* buf, bool lenient = false); int32_t ToUnicode(MaybeStackBuffer* buf, const char* input, - size_t length, - bool lenient = false); + size_t length); } // namespace i18n } // namespace node diff --git a/test/fixtures/url-idna.js b/test/fixtures/url-idna.js index f105adeed12..cbfe702e937 100644 --- a/test/fixtures/url-idna.js +++ b/test/fixtures/url-idna.js @@ -191,22 +191,33 @@ module.exports = { { ascii: `${`${'a'.repeat(64)}.`.repeat(4)}com`, unicode: `${`${'a'.repeat(64)}.`.repeat(4)}com` - } - ], - invalid: [ - // invalid character + }, + // URLs with hyphen + { + ascii: 'r4---sn-a5mlrn7s.gevideo.com', + unicode: 'r4---sn-a5mlrn7s.gevideo.com' + }, + { + ascii: '-sn-a5mlrn7s.gevideo.com', + unicode: '-sn-a5mlrn7s.gevideo.com' + }, { - url: '\ufffd.com', - mode: 'ascii' + ascii: 'sn-a5mlrn7s-.gevideo.com', + unicode: 'sn-a5mlrn7s-.gevideo.com' }, { - url: '\ufffd.com', - mode: 'unicode' + ascii: '-sn-a5mlrn7s-.gevideo.com', + unicode: '-sn-a5mlrn7s-.gevideo.com' }, - // invalid Punycode { - url: 'xn---abc.com', - mode: 'unicode' + ascii: '-sn--a5mlrn7s-.gevideo.com', + unicode: '-sn--a5mlrn7s-.gevideo.com' } + ], + invalid: [ + // invalid character + '\ufffd.com', + // invalid bi-directional character + 'تشادرlatin.icom.museum' ] } diff --git a/test/parallel/test-icu-punycode.js b/test/parallel/test-icu-punycode.js index 411704bb8f4..ba2014bdc85 100644 --- a/test/parallel/test-icu-punycode.js +++ b/test/parallel/test-icu-punycode.js @@ -23,19 +23,13 @@ const tests = require('../fixtures/url-idna.js'); } { - const errorRe = { - ascii: /^Error: Cannot convert name to ASCII$/, - unicode: /^Error: Cannot convert name to Unicode$/ - }; - const convertFunc = { - ascii: icu.toASCII, - unicode: icu.toUnicode - }; - - for (const [i, { url, mode }] of tests.invalid.entries()) { - assert.throws(() => convertFunc[mode](url), errorRe[mode], - `Invalid case ${i + 1}`); - assert.doesNotThrow(() => convertFunc[mode](url, true), - `Invalid case ${i + 1} in lenient mode`); + for (const [i, url] of tests.invalid.entries()) { + assert.throws(() => icu.toASCII(url), + /^Error: Cannot convert name to ASCII$/, + `ToASCII invalid case ${i + 1}`); + assert.doesNotThrow(() => icu.toASCII(url, true), + `ToASCII invalid case ${i + 1} in lenient mode`); + assert.doesNotThrow(() => icu.toUnicode(url), + `ToUnicode invalid case ${i + 1}`); } } diff --git a/test/parallel/test-url-domain-ascii-unicode.js b/test/parallel/test-url-domain-ascii-unicode.js index dcc918201bb..9c288cb6e29 100644 --- a/test/parallel/test-url-domain-ascii-unicode.js +++ b/test/parallel/test-url-domain-ascii-unicode.js @@ -8,7 +8,8 @@ const domainToASCII = url.domainToASCII; const domainToUnicode = url.domainToUnicode; const domainWithASCII = [ - ['ıídيٴ', 'xn--d-iga7ro0q9f'], + ['ıíd', 'xn--d-iga7r'], + ['يٴ', 'xn--mhb8f'], ['www.ϧƽəʐ.com', 'www.xn--cja62apfr6c.com'], ['новини.com', 'xn--b1amarcd.com'], ['名がドメイン.com', 'xn--v8jxj3d1dzdz08w.com'], diff --git a/test/parallel/test-whatwg-url-domainto.js b/test/parallel/test-whatwg-url-domainto.js index 13ff9968705..90d9ee4a8c4 100644 --- a/test/parallel/test-whatwg-url-domainto.js +++ b/test/parallel/test-whatwg-url-domainto.js @@ -35,11 +35,8 @@ const tests = require('../fixtures/url-idna.js'); } { - const convertFunc = { - ascii: domainToASCII, - unicode: domainToUnicode - }; - - for (const [i, { url, mode }] of tests.invalid.entries()) - assert.strictEqual(convertFunc[mode](url), '', `Invalid case ${i + 1}`); + for (const [i, url] of tests.invalid.entries()) { + assert.strictEqual(domainToASCII(url), '', `Invalid case ${i + 1}`); + assert.strictEqual(domainToUnicode(url), '', `Invalid case ${i + 1}`); + } } From c60a7fa7383a983a0348e8876fdd84b04c353436 Mon Sep 17 00:00:00 2001 From: Artur G Vieira Date: Mon, 15 May 2017 03:38:54 +0000 Subject: [PATCH 11/12] test: move net reconnect error test to sequential The usage of common.PORT could cause undesired port collisions when run in parallel. The following test was moved to sequential. test-net-reconnect-error.js PR-URL: https://github.com/nodejs/node/pull/13033 Refs: https://github.com/nodejs/node/issues/12376 Reviewed-By: Rich Trott Reviewed-By: Luigi Pinca Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Refael Ackermann --- .../test-net-reconnect-error.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) rename test/{parallel => sequential}/test-net-reconnect-error.js (90%) diff --git a/test/parallel/test-net-reconnect-error.js b/test/sequential/test-net-reconnect-error.js similarity index 90% rename from test/parallel/test-net-reconnect-error.js rename to test/sequential/test-net-reconnect-error.js index d9a68e01d07..128feffc933 100644 --- a/test/parallel/test-net-reconnect-error.js +++ b/test/sequential/test-net-reconnect-error.js @@ -27,22 +27,19 @@ const N = 20; let client_error_count = 0; let disconnect_count = 0; -// Hopefully nothing is running on common.PORT const c = net.createConnection(common.PORT); c.on('connect', common.mustNotCall('client should not have connected')); -c.on('error', function(e) { - console.error(`CLIENT error: ${e.code}`); +c.on('error', common.mustCall((e) => { client_error_count++; assert.strictEqual('ECONNREFUSED', e.code); -}); +}, N + 1)); -c.on('close', function() { - console.log('CLIENT disconnect'); +c.on('close', common.mustCall(() => { if (disconnect_count++ < N) c.connect(common.PORT); // reconnect -}); +}, N + 1)); process.on('exit', function() { assert.strictEqual(N + 1, disconnect_count); From 8250bfd1e5188d5dada58aedf7a991e959d5eaa9 Mon Sep 17 00:00:00 2001 From: Myles Borins Date: Thu, 11 May 2017 18:52:20 +0300 Subject: [PATCH 12/12] fs: Revert throw on invalid callbacks This reverts 4cb5f3daa350421e4eb4622dc818633d3a0659b3 Based on community feedback I think we should consider reverting this change. We should explore how this could be solved via linting rules. Refs: https://github.com/nodejs/node/pull/12562 PR-URL: https://github.com/nodejs/node/pull/12976 Reviewed-By: Sakthipriyan Vairamani Reviewed-By: Evan Lucas Reviewed-By: Colin Ihrig Reviewed-By: Rich Trott --- doc/api/deprecations.md | 5 +- doc/api/fs.md | 180 ++++----------------- lib/fs.js | 60 +++++-- test/fixtures/test-fs-readfile-error.js | 2 +- test/parallel/test-fs-access.js | 4 +- test/parallel/test-fs-link.js | 4 +- test/parallel/test-fs-make-callback.js | 8 +- test/parallel/test-fs-makeStatsCallback.js | 8 +- test/parallel/test-fs-mkdtemp.js | 5 + test/parallel/test-fs-readfile-error.js | 2 +- test/parallel/test-fs-write-no-fd.js | 6 +- 11 files changed, 104 insertions(+), 180 deletions(-) diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 82c115d02f1..96e9f927d34 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -150,10 +150,9 @@ explicitly via error event handlers set on the domain instead. ### DEP0013: fs async function without callback -Type: End-of-Life +Type: Runtime -Calling an asynchronous function without a callback will throw a `TypeError` -v8.0.0 onwards. Refer: [PR 12562](https://github.com/nodejs/node/pull/12562) +Calling an asynchronous function without a callback is deprecated. ### DEP0014: fs.read legacy String interface diff --git a/doc/api/fs.md b/doc/api/fs.md index e867e994349..16311dead44 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -551,14 +551,10 @@ checks fail, and does nothing otherwise. * `path` {string|Buffer|URL} @@ -663,10 +655,6 @@ Synchronous chmod(2). Returns `undefined`. * `path` {string|Buffer|URL} @@ -705,14 +693,10 @@ Synchronous chown(2). Returns `undefined`. * `fd` {integer} @@ -1003,14 +987,10 @@ a callback.) * `fd` {integer} @@ -1034,14 +1014,10 @@ Synchronous fchmod(2). Returns `undefined`. * `fd` {integer} @@ -1067,14 +1043,10 @@ Synchronous fchown(2). Returns `undefined`. * `fd` {integer} @@ -1096,14 +1068,10 @@ Synchronous fdatasync(2). Returns `undefined`. * `fd` {integer} @@ -1126,14 +1094,10 @@ Synchronous fstat(2). Returns an instance of [`fs.Stats`][]. * `fd` {integer} @@ -1155,14 +1119,10 @@ Synchronous fsync(2). Returns `undefined`. * `fd` {integer} @@ -1227,14 +1187,10 @@ Synchronous ftruncate(2). Returns `undefined`. * `path` {string|Buffer} @@ -1302,14 +1254,10 @@ Synchronous lchmod(2). Returns `undefined`. * `path` {string|Buffer} @@ -1335,10 +1283,6 @@ Synchronous lchown(2). Returns `undefined`. * `existingPath` {string|Buffer|URL} @@ -1377,10 +1321,6 @@ Synchronous link(2). Returns `undefined`. * `path` {string|Buffer|URL} @@ -1417,10 +1357,6 @@ Synchronous lstat(2). Returns an instance of [`fs.Stats`][]. * `path` {string|Buffer|URL} @@ -1457,14 +1393,10 @@ Synchronous mkdir(2). Returns `undefined`. * `path` {string|Buffer|URL} @@ -1920,10 +1840,6 @@ Synchronous version of [`fs.read()`][]. Returns the number of `bytesRead`. * `oldPath` {string|Buffer|URL} @@ -2032,10 +1944,6 @@ Synchronous rename(2). Returns `undefined`. * `path` {string|Buffer|URL} @@ -2070,10 +1978,6 @@ Synchronous rmdir(2). Returns `undefined`. * `path` {string|Buffer|URL} @@ -2166,14 +2070,10 @@ Synchronous symlink(2). Returns `undefined`. * `path` {string|Buffer} @@ -2199,10 +2099,6 @@ passed as the first argument. In this case, `fs.ftruncateSync()` is called. * `path` {string|Buffer|URL} @@ -2256,10 +2152,6 @@ when possible. * `fd` {integer} @@ -2526,17 +2414,13 @@ the end of the file. * `fd` {integer} @@ -2574,17 +2458,13 @@ the end of the file.