diff --git a/CHANGELOG.md b/CHANGELOG.md index bddf738e117443..f7d1c7d3e2007e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,8 @@ release. 12.0.0
-10.18.0
+10.18.1
+10.18.0
10.17.0
10.16.3
10.16.2
diff --git a/common.gypi b/common.gypi index 770f99955a26cc..f5786ef89f209f 100644 --- a/common.gypi +++ b/common.gypi @@ -33,7 +33,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.54', + 'v8_embedder_string': '-node.55', # Enable disassembler for `--print-code` v8 options 'v8_enable_disassembler': 1, diff --git a/configure.py b/configure.py index cfd4207d32b8b9..22861a10eeac54 100755 --- a/configure.py +++ b/configure.py @@ -709,7 +709,7 @@ def get_llvm_version(cc): def get_xcode_version(cc): return get_version_helper( - cc, r"(^Apple LLVM version) ([0-9]+\.[0-9]+)") + cc, r"(^Apple (?:clang|LLVM) version) ([0-9]+\.[0-9]+)") def get_gas_version(cc): try: diff --git a/deps/icu-small/source/data/in/icudt64l.dat b/deps/icu-small/source/data/in/icudt64l.dat index 113b88a4804805..2dcbc120a157ae 100644 Binary files a/deps/icu-small/source/data/in/icudt64l.dat and b/deps/icu-small/source/data/in/icudt64l.dat differ diff --git a/deps/v8/src/objects/intl-objects.cc b/deps/v8/src/objects/intl-objects.cc index 60c3a0721be228..714099893d903a 100644 --- a/deps/v8/src/objects/intl-objects.cc +++ b/deps/v8/src/objects/intl-objects.cc @@ -138,7 +138,9 @@ icu::SimpleDateFormat* CreateICUDateFormat(Isolate* isolate, status)); icu::UnicodeString pattern; if (U_SUCCESS(status)) - pattern = generator->getBestPattern(skeleton, status); + pattern = generator->getBestPattern(skeleton, + UDATPG_MATCH_HOUR_FIELD_LENGTH, + status); date_format = new icu::SimpleDateFormat(pattern, icu_locale, status); if (U_SUCCESS(status)) { diff --git a/deps/v8/test/intl/regress-527926.js b/deps/v8/test/intl/regress-527926.js new file mode 100644 index 00000000000000..3f464794da19e3 --- /dev/null +++ b/deps/v8/test/intl/regress-527926.js @@ -0,0 +1,19 @@ +// Copyright 2019 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let date = new Date(2015, 8, 1, 3, 0, 0); +var fmt = new Intl.DateTimeFormat('ru', {hour:'2-digit', minute: '2-digit'}) +assertEquals("03:00", fmt.format(date)); + +fmt = new Intl.DateTimeFormat( + 'en', {hour:'2-digit', minute: '2-digit', hour12: false}); +assertEquals("03:00", fmt.format(date)); + +fmt = new Intl.DateTimeFormat( + 'ru', {hour:'2-digit', minute: '2-digit', hour12: false}); +assertEquals("03:00", fmt.format(date)); + +fmt = new Intl.DateTimeFormat( + 'ru', {hour:'2-digit', minute: '2-digit', hour12: true}); +assertEquals("03:00 AM", fmt.format(date)); diff --git a/doc/api/dns.md b/doc/api/dns.md index a4e83ee9712e0c..7eb178e328f766 100644 --- a/doc/api/dns.md +++ b/doc/api/dns.md @@ -56,7 +56,7 @@ dns.resolve4('archive.org', (err, addresses) => { There are subtle consequences in choosing one over the other, please consult the [Implementation considerations section][] for more information. -## Class: dns.Resolver +## Class: `dns.Resolver` @@ -97,7 +97,7 @@ The following methods from the `dns` module are available: * [`resolver.reverse()`][`dns.reverse()`] * [`resolver.setServers()`][`dns.setServers()`] -### resolver.cancel() +### `resolver.cancel()` @@ -105,7 +105,7 @@ added: v8.3.0 Cancel all outstanding DNS queries made by this resolver. The corresponding callbacks will be called with an error with code `ECANCELLED`. -## dns.getServers() +## `dns.getServers()` @@ -126,7 +126,7 @@ section if a custom port is used. ] ``` -## dns.lookup(hostname[, options], callback) +## `dns.lookup(hostname[, options], callback)` @@ -243,7 +243,7 @@ dns.lookupService('127.0.0.1', 22, (err, hostname, service) => { If this method is invoked as its [`util.promisify()`][]ed version, it returns a `Promise` for an `Object` with `hostname` and `service` properties. -## dns.resolve(hostname[, rrtype], callback) +## `dns.resolve(hostname[, rrtype], callback)` @@ -275,7 +275,7 @@ records. The type and structure of individual results varies based on `rrtype`: On error, `err` is an [`Error`][] object, where `err.code` is one of the [DNS error codes](#dns_error_codes). -## dns.resolve4(hostname[, options], callback) +## `dns.resolve4(hostname[, options], callback)` @@ -385,7 +385,7 @@ Uses the DNS protocol to resolve `CNAME` records for the `hostname`. The will contain an array of canonical name records available for the `hostname` (e.g. `['bar.example.com']`). -## dns.resolveMx(hostname, callback) +## `dns.resolveMx(hostname, callback)` @@ -399,7 +399,7 @@ Uses the DNS protocol to resolve mail exchange records (`MX` records) for the contain an array of objects containing both a `priority` and `exchange` property (e.g. `[{priority: 10, exchange: 'mx.example.com'}, ...]`). -## dns.resolveNaptr(hostname, callback) +## `dns.resolveNaptr(hostname, callback)` @@ -431,7 +431,7 @@ function will contain an array of objects with the following properties: } ``` -## dns.resolveNs(hostname, callback) +## `dns.resolveNs(hostname, callback)` @@ -445,7 +445,7 @@ Uses the DNS protocol to resolve name server records (`NS` records) for the contain an array of name server records available for `hostname` (e.g. `['ns1.example.com', 'ns2.example.com']`). -## dns.resolvePtr(hostname, callback) +## `dns.resolvePtr(hostname, callback)` @@ -458,7 +458,7 @@ Uses the DNS protocol to resolve pointer records (`PTR` records) for the `hostname`. The `addresses` argument passed to the `callback` function will be an array of strings containing the reply records. -## dns.resolveSoa(hostname, callback) +## `dns.resolveSoa(hostname, callback)` @@ -492,7 +492,7 @@ be an object with the following properties: } ``` -## dns.resolveSrv(hostname, callback) +## `dns.resolveSrv(hostname, callback)` @@ -520,7 +520,7 @@ be an array of objects with the following properties: } ``` -## dns.resolveTxt(hostname, callback) +## `dns.resolveTxt(hostname, callback)` @@ -536,7 +536,7 @@ two-dimensional array of the text records available for `hostname` (e.g. one record. Depending on the use case, these could be either joined together or treated separately. -## dns.reverse(ip, callback) +## `dns.reverse(ip, callback)` @@ -551,7 +551,7 @@ array of hostnames. On error, `err` is an [`Error`][] object, where `err.code` is one of the [DNS error codes][]. -## dns.setServers(servers) +## `dns.setServers(servers)` @@ -594,7 +594,7 @@ The `dns.promises` API provides an alternative set of asynchronous DNS methods that return `Promise` objects rather than using callbacks. The API is accessible via `require('dns').promises`. -### Class: dnsPromises.Resolver +### Class: `dnsPromises.Resolver` @@ -640,7 +640,7 @@ The following methods from the `dnsPromises` API are available: * [`resolver.reverse()`][`dnsPromises.reverse()`] * [`resolver.setServers()`][`dnsPromises.setServers()`] -### dnsPromises.getServers() +### `dnsPromises.getServers()` @@ -661,7 +661,7 @@ section if a custom port is used. ] ``` -### dnsPromises.lookup(hostname[, options]) +### `dnsPromises.lookup(hostname[, options])` @@ -724,7 +724,7 @@ dnsPromises.lookup('example.com', options).then((result) => { }); ``` -### dnsPromises.lookupService(address, port) +### `dnsPromises.lookupService(address, port)` @@ -749,7 +749,7 @@ dnsPromises.lookupService('127.0.0.1', 22).then((result) => { }); ``` -### dnsPromises.resolve(hostname[, rrtype]) +### `dnsPromises.resolve(hostname[, rrtype])` @@ -778,7 +778,7 @@ based on `rrtype`: On error, the `Promise` is rejected with an [`Error`][] object, where `err.code` is one of the [DNS error codes](#dns_error_codes). -### dnsPromises.resolve4(hostname[, options]) +### `dnsPromises.resolve4(hostname[, options])` @@ -793,7 +793,7 @@ Uses the DNS protocol to resolve IPv4 addresses (`A` records) for the `hostname`. On success, the `Promise` is resolved with an array of IPv4 addresses (e.g. `['74.125.79.104', '74.125.79.105', '74.125.79.106']`). -### dnsPromises.resolve6(hostname[, options]) +### `dnsPromises.resolve6(hostname[, options])` @@ -808,7 +808,7 @@ Uses the DNS protocol to resolve IPv6 addresses (`AAAA` records) for the `hostname`. On success, the `Promise` is resolved with an array of IPv6 addresses. -### dnsPromises.resolveAny(hostname) +### `dnsPromises.resolveAny(hostname)` @@ -852,7 +852,7 @@ Here is an example of the result object: minttl: 60 } ] ``` -### dnsPromises.resolveCname(hostname) +### `dnsPromises.resolveCname(hostname)` @@ -862,7 +862,7 @@ Uses the DNS protocol to resolve `CNAME` records for the `hostname`. On success, the `Promise` is resolved with an array of canonical name records available for the `hostname` (e.g. `['bar.example.com']`). -### dnsPromises.resolveMx(hostname) +### `dnsPromises.resolveMx(hostname)` @@ -873,7 +873,7 @@ Uses the DNS protocol to resolve mail exchange records (`MX` records) for the containing both a `priority` and `exchange` property (e.g. `[{priority: 10, exchange: 'mx.example.com'}, ...]`). -### dnsPromises.resolveNaptr(hostname) +### `dnsPromises.resolveNaptr(hostname)` @@ -902,7 +902,7 @@ of objects with the following properties: } ``` -### dnsPromises.resolveNs(hostname) +### `dnsPromises.resolveNs(hostname)` @@ -913,7 +913,7 @@ Uses the DNS protocol to resolve name server records (`NS` records) for the records available for `hostname` (e.g. `['ns1.example.com', 'ns2.example.com']`). -### dnsPromises.resolvePtr(hostname) +### `dnsPromises.resolvePtr(hostname)` @@ -923,7 +923,7 @@ Uses the DNS protocol to resolve pointer records (`PTR` records) for the `hostname`. On success, the `Promise` is resolved with an array of strings containing the reply records. -### dnsPromises.resolveSoa(hostname) +### `dnsPromises.resolveSoa(hostname)` @@ -954,7 +954,7 @@ following properties: } ``` -### dnsPromises.resolveSrv(hostname) +### `dnsPromises.resolveSrv(hostname)` @@ -979,7 +979,7 @@ the following properties: } ``` -### dnsPromises.resolveTxt(hostname) +### `dnsPromises.resolveTxt(hostname)` @@ -992,7 +992,7 @@ of the text records available for `hostname` (e.g. one record. Depending on the use case, these could be either joined together or treated separately. -### dnsPromises.reverse(ip) +### `dnsPromises.reverse(ip)` @@ -1004,7 +1004,7 @@ array of hostnames. On error, the `Promise` is rejected with an [`Error`][] object, where `err.code` is one of the [DNS error codes](#dns_error_codes). -### dnsPromises.setServers(servers) +### `dnsPromises.setServers(servers)` diff --git a/doc/api/stream.md b/doc/api/stream.md index b6da7d98a1f94d..2d437c0eacef3b 100644 --- a/doc/api/stream.md +++ b/doc/api/stream.md @@ -1010,6 +1010,8 @@ buffer will be returned. If the `size` argument is not specified, all of the data contained in the internal buffer will be returned. +The `size` argument must be less than or equal to 1 GB. + The `readable.read()` method should only be called on `Readable` streams operating in paused mode. In flowing mode, `readable.read()` is called automatically until the internal buffer is fully drained. diff --git a/doc/api_assets/style.css b/doc/api_assets/style.css index bdef22b04f78c9..ecb9208135db48 100644 --- a/doc/api_assets/style.css +++ b/doc/api_assets/style.css @@ -20,18 +20,28 @@ body { background: #fff; } -h1 { font-size: 2.5rem } -h2 { font-size: 2rem } -h3 { font-size: 1.75rem } -h4 { font-size: 1.5rem } -h5 { font-size: 1.25rem } -h6 { font-size: 1rem } - -h1, h2, h3, h4, h5, h6 { - margin: 1.5rem 0 1rem; - text-rendering: optimizeLegibility; +h1, h1 code { font-size: 2.5rem; } +h2, h2 code { font-size: 2rem; } +h3, h3 code { font-size: 1.75rem; } +h4, h4 code { font-size: 1.5rem; } +h5, h5 code { font-size: 1.25rem; } +h6, h6 code { font-size: 1rem; } + +h1, h1 code, +h2, h2 code, +h3, h3 code, +h4, h4 code, +h5, h5 code, +h6, h6 code { + background-color: inherit; + color: inherit; + font-family: inherit; font-weight: 700; + line-height: inherit; + margin: 1.5rem 0 1rem; + padding: inherit; position: relative; + text-rendering: optimizeLegibility; } pre, tt, code, .pre, span.type, a.type { diff --git a/doc/changelogs/CHANGELOG_V10.md b/doc/changelogs/CHANGELOG_V10.md index 1b97546cb3ee7c..2b02844a6a06bc 100644 --- a/doc/changelogs/CHANGELOG_V10.md +++ b/doc/changelogs/CHANGELOG_V10.md @@ -10,6 +10,7 @@ +10.18.1
10.18.0
10.17.0
10.16.3
@@ -57,6 +58,33 @@ * [io.js](CHANGELOG_IOJS.md) * [Archive](CHANGELOG_ARCHIVE.md) + +## 2020-01-09, Version 10.18.1 'Dubnium' (LTS), @BethGriggs + +### Notable changes + +* **http2**: fix session memory accounting after pausing (Michael Lehenbauer) [#30684](https://github.com/nodejs/node/pull/30684) +* **n-api**: correct bug in napi_get_last_error (Octavian Soldea) [#28702](https://github.com/nodejs/node/pull/28702) +* **tools**: update tzdata to 2019c (Myles Borins) [#30479](https://github.com/nodejs/node/pull/30479) + +### Commits + +* [[`a80c59130e`](https://github.com/nodejs/node/commit/a80c59130e)] - **build**: fix configure script to work with Apple Clang 11 (Saagar Jha) [#28071](https://github.com/nodejs/node/pull/28071) +* [[`68b2b5cc51`](https://github.com/nodejs/node/commit/68b2b5cc51)] - **build,win**: propagate error codes in vcbuild (João Reis) [#30724](https://github.com/nodejs/node/pull/30724) +* [[`3e0709cf5e`](https://github.com/nodejs/node/commit/3e0709cf5e)] - **deps**: V8: backport fb63e5cf55e9 (Michaël Zasso) +* [[`25b8fbda35`](https://github.com/nodejs/node/commit/25b8fbda35)] - **doc**: allow in header elements (Rich Trott) [#31086](https://github.com/nodejs/node/pull/31086) +* [[`a1b095dd46`](https://github.com/nodejs/node/commit/a1b095dd46)] - **doc,dns**: use code markup/markdown in headers (Rich Trott) [#31086](https://github.com/nodejs/node/pull/31086) +* [[`8f3b8ca515`](https://github.com/nodejs/node/commit/8f3b8ca515)] - **http2**: fix session memory accounting after pausing (Michael Lehenbauer) [#30684](https://github.com/nodejs/node/pull/30684) +* [[`20f64a96de`](https://github.com/nodejs/node/commit/20f64a96de)] - **http2**: use the latest settings (ZYSzys) [#29780](https://github.com/nodejs/node/pull/29780) +* [[`81c31005fd`](https://github.com/nodejs/node/commit/81c31005fd)] - **lib**: fix comment nits in bootstrap\loaders.js (Vse Mozhet Byt) [#24641](https://github.com/nodejs/node/pull/24641) +* [[`88e8b7cf83`](https://github.com/nodejs/node/commit/88e8b7cf83)] - **n-api**: correct bug in napi_get_last_error (Octavian Soldea) [#28702](https://github.com/nodejs/node/pull/28702) +* [[`77e0318849`](https://github.com/nodejs/node/commit/77e0318849)] - **stream**: increase MAX_HWM (Robert Nagy) [#29938](https://github.com/nodejs/node/pull/29938) +* [[`894aaa2040`](https://github.com/nodejs/node/commit/894aaa2040)] - **stream**: extract Readable.from in its own file (Matteo Collina) [#30140](https://github.com/nodejs/node/pull/30140) +* [[`7e941eb17d`](https://github.com/nodejs/node/commit/7e941eb17d)] - **test**: do not fail SLOW tests if they are not slow (Yang Guo) [#25868](https://github.com/nodejs/node/pull/25868) +* [[`0f3ae77aaf`](https://github.com/nodejs/node/commit/0f3ae77aaf)] - **tools**: update tzdata to 2019c (Myles Borins) [#30479](https://github.com/nodejs/node/pull/30479) +* [[`4ae8d204cb`](https://github.com/nodejs/node/commit/4ae8d204cb)] - **tools**: move python code out of jenkins shell (Sam Roberts) [#28458](https://github.com/nodejs/node/pull/28458) +* [[`4879b80d87`](https://github.com/nodejs/node/commit/4879b80d87)] - **tools**: fix v8 testing with devtoolset on ppcle (Sam Roberts) [#28458](https://github.com/nodejs/node/pull/28458) + ## 2019-12-17, Version 10.18.0 'Dubnium' (LTS), @MylesBorins diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index 88193cd3b76219..98216b411f5862 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -42,6 +42,7 @@ const { // Lazy loaded to improve the startup performance. let StringDecoder; let createReadableStreamAsyncIterator; +let from; util.inherits(Readable, Stream); @@ -339,10 +340,11 @@ Readable.prototype.setEncoding = function(enc) { return this; }; -// Don't raise the hwm > 8MB -const MAX_HWM = 0x800000; +// Don't raise the hwm > 1GB +const MAX_HWM = 0x40000000; function computeNewHighWaterMark(n) { if (n >= MAX_HWM) { + // TODO(ronag): Throw ERR_VALUE_OUT_OF_RANGE. n = MAX_HWM; } else { // Get the next highest power of 2 to prevent increasing hwm excessively in @@ -1154,40 +1156,8 @@ function endReadableNT(state, stream) { } Readable.from = function(iterable, opts) { - let iterator; - if (iterable && iterable[Symbol.asyncIterator]) - iterator = iterable[Symbol.asyncIterator](); - else if (iterable && iterable[Symbol.iterator]) - iterator = iterable[Symbol.iterator](); - else - throw new ERR_INVALID_ARG_TYPE('iterable', ['Iterable'], iterable); - - const readable = new Readable({ - objectMode: true, - ...opts - }); - // Reading boolean to protect against _read - // being called before last iteration completion. - let reading = false; - readable._read = function() { - if (!reading) { - reading = true; - next(); - } - }; - async function next() { - try { - const { value, done } = await iterator.next(); - if (done) { - readable.push(null); - } else if (readable.push(await value)) { - next(); - } else { - reading = false; - } - } catch (err) { - readable.destroy(err); - } + if (from === undefined) { + from = require('internal/streams/from'); } - return readable; + return from(Readable, iterable, opts); }; diff --git a/lib/internal/bootstrap/loaders.js b/lib/internal/bootstrap/loaders.js index 06aee591496440..89087320ed0913 100644 --- a/lib/internal/bootstrap/loaders.js +++ b/lib/internal/bootstrap/loaders.js @@ -19,7 +19,7 @@ // can be created using NODE_MODULE_CONTEXT_AWARE_CPP() with the flag // NM_F_LINKED. // - internalBinding(): the private internal C++ binding loader, inaccessible -// from user land because they are only available from NativeModule.require() +// from user land because they are only available from NativeModule.require(). // These C++ bindings are created using NODE_MODULE_CONTEXT_AWARE_INTERNAL() // and have their nm_flags set to NM_F_INTERNAL. // @@ -61,7 +61,7 @@ keys: ObjectKeys, } = Object; - // Set up process.moduleLoadList + // Set up process.moduleLoadList. const moduleLoadList = []; ObjectDefineProperty(process, 'moduleLoadList', { value: moduleLoadList, @@ -70,7 +70,7 @@ writable: false }); - // Set up process.binding() and process._linkedBinding() + // Set up process.binding() and process._linkedBinding(). { const bindingObj = ObjectCreate(null); @@ -93,7 +93,7 @@ }; } - // Set up internalBinding() in the closure + // Set up internalBinding() in the closure. let internalBinding; { const bindingObj = ObjectCreate(null); @@ -115,11 +115,11 @@ }; } - // Create this WeakMap in js-land because V8 has no C++ API for WeakMap + // Create this WeakMap in js-land because V8 has no C++ API for WeakMap. internalBinding('module_wrap').callbackMap = new WeakMap(); const { ContextifyScript } = process.binding('contextify'); - // Set up NativeModule + // Set up NativeModule. function NativeModule(id) { this.filename = `${id}.js`; this.id = id; @@ -128,7 +128,7 @@ this.exportKeys = undefined; this.loaded = false; this.loading = false; - this.script = null; // The ContextifyScript of the module + this.script = null; // The ContextifyScript of the module. } NativeModule._source = getBinding('natives'); @@ -160,7 +160,7 @@ if (!NativeModule.exists(id)) { // Model the error off the internal/errors.js model, but // do not use that module given that it could actually be - // the one causing the error if there's a bug in Node.js + // the one causing the error if there's a bug in Node.js. // eslint-disable-next-line no-restricted-syntax const err = new Error(`No such built-in module: ${id}`); err.code = 'ERR_UNKNOWN_BUILTIN_MODULE'; @@ -201,7 +201,7 @@ if (config.exposeInternals) { NativeModule.nonInternalExists = function(id) { - // Do not expose this to user land even with --expose-internals + // Do not expose this to user land even with --expose-internals. if (id === loaderId) { return false; } @@ -209,7 +209,7 @@ }; NativeModule.isInternal = function(id) { - // Do not expose this to user land even with --expose-internals + // Do not expose this to user land even with --expose-internals. return id === loaderId; }; } else { @@ -243,7 +243,7 @@ }; // Provide named exports for all builtin libraries so that the libraries - // may be imported in a nicer way for esm users. The default export is left + // may be imported in a nicer way for ESM users. The default export is left // as the entire namespace (module.exports) and wrapped in a proxy such // that APMs and other behavior are still left intact. NativeModule.prototype.proxifyExports = function() { diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index 5046539c570841..bb9e43ca8ea0bc 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -504,6 +504,7 @@ function onSettings() { return; session[kUpdateTimer](); debugSessionObj(session, 'new settings received'); + session[kRemoteSettings] = undefined; session.emit('remoteSettings', session.remoteSettings); } diff --git a/lib/internal/streams/from.js b/lib/internal/streams/from.js new file mode 100644 index 00000000000000..e809f2658d5a9a --- /dev/null +++ b/lib/internal/streams/from.js @@ -0,0 +1,46 @@ +'use strict'; + +const { + ERR_INVALID_ARG_TYPE +} = require('internal/errors').codes; + +function from(Readable, iterable, opts) { + let iterator; + if (iterable && iterable[Symbol.asyncIterator]) + iterator = iterable[Symbol.asyncIterator](); + else if (iterable && iterable[Symbol.iterator]) + iterator = iterable[Symbol.iterator](); + else + throw new ERR_INVALID_ARG_TYPE('iterable', ['Iterable'], iterable); + + const readable = new Readable({ + objectMode: true, + ...opts + }); + // Reading boolean to protect against _read + // being called before last iteration completion. + let reading = false; + readable._read = function() { + if (!reading) { + reading = true; + next(); + } + }; + async function next() { + try { + const { value, done } = await iterator.next(); + if (done) { + readable.push(null); + } else if (readable.push(await value)) { + next(); + } else { + reading = false; + } + } catch (err) { + readable.destroy(err); + } + } + return readable; +} + +module.exports = from; diff --git a/node.gyp b/node.gyp index e50a284b3011f0..dd60ea4a937691 100644 --- a/node.gyp +++ b/node.gyp @@ -178,6 +178,7 @@ 'lib/internal/streams/async_iterator.js', 'lib/internal/streams/buffer_list.js', 'lib/internal/streams/duplexpair.js', + 'lib/internal/streams/from.js', 'lib/internal/streams/legacy.js', 'lib/internal/streams/destroy.js', 'lib/internal/streams/state.js', diff --git a/src/node_api.cc b/src/node_api.cc index f04a5bbfb930a9..39b4fe8bca595f 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -1407,14 +1407,16 @@ napi_status napi_get_last_error_info(napi_env env, CHECK_ENV(env); CHECK_ARG(env, result); - // you must update this assert to reference the last message - // in the napi_status enum each time a new error message is added. + // The value of the constant below must be updated to reference the last + // message in the `napi_status` enum each time a new error message is added. // We don't have a napi_status_last as this would result in an ABI // change each time a message was added. + const int last_status = napi_date_expected; + static_assert( - node::arraysize(error_messages) == napi_date_expected + 1, + node::arraysize(error_messages) == last_status + 1, "Count of error messages must match count of error values"); - CHECK_LE(env->last_error.error_code, napi_callback_scope_mismatch); + CHECK_LE(env->last_error.error_code, last_status); // Wait until someone requests the last error information to fetch the error // message string diff --git a/src/node_api_types.h b/src/node_api_types.h index 0aece04aeef85b..211e4611c2d70b 100644 --- a/src/node_api_types.h +++ b/src/node_api_types.h @@ -84,6 +84,10 @@ typedef enum { napi_bigint_expected, napi_date_expected, } napi_status; +// Note: when adding a new enum value to `napi_status`, please also update +// `const int last_status` in `napi_get_last_error_info()' definition, +// in file js_native_api_v8.cc. Please also update the definition of +// `napi_status` in doc/api/n-api.md to reflect the newly added value(s). #if NAPI_VERSION >= 4 typedef enum { diff --git a/src/node_http2.cc b/src/node_http2.cc index 21051e1721965b..35e0e8f623e3e6 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -1937,7 +1937,10 @@ void Http2Session::OnStreamRead(ssize_t nread, const uv_buf_t& buf_) { buf = uv_buf_init(new_buf, nread); stream_buf_offset_ = 0; stream_buf_ab_.Reset(); - DecrementCurrentSessionMemory(stream_buf_offset_); + + // We have now fully processed the stream_buf_ input chunk (by moving the + // remaining part into buf, which will be accounted for below). + DecrementCurrentSessionMemory(stream_buf_.len); } // Shrink to the actual amount of used data. diff --git a/src/node_version.h b/src/node_version.h index 37671594fcaed2..13151531830c7b 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -29,7 +29,7 @@ #define NODE_VERSION_IS_LTS 1 #define NODE_VERSION_LTS_CODENAME "Dubnium" -#define NODE_VERSION_IS_RELEASE 0 +#define NODE_VERSION_IS_RELEASE 1 #ifndef NODE_STRINGIFY #define NODE_STRINGIFY(n) NODE_STRINGIFY_HELPER(n) diff --git a/test/parallel/test-http2-large-writes-session-memory-leak.js b/test/parallel/test-http2-large-writes-session-memory-leak.js new file mode 100644 index 00000000000000..641923c06c9133 --- /dev/null +++ b/test/parallel/test-http2-large-writes-session-memory-leak.js @@ -0,0 +1,55 @@ +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const fixtures = require('../common/fixtures'); +const http2 = require('http2'); + +// Regression test for https://github.com/nodejs/node/issues/29223. +// There was a "leak" in the accounting of session memory leading +// to streams eventually failing with NGHTTP2_ENHANCE_YOUR_CALM. + +const server = http2.createSecureServer({ + key: fixtures.readKey('agent2-key.pem'), + cert: fixtures.readKey('agent2-cert.pem'), +}); + +// Simple server that sends 200k and closes the stream. +const data200k = 'a'.repeat(200 * 1024); +server.on('stream', (stream) => { + stream.write(data200k); + stream.end(); +}); + +server.listen(0, common.mustCall(() => { + const client = http2.connect(`https://localhost:${server.address().port}`, { + ca: fixtures.readKey('agent2-cert.pem'), + servername: 'agent2', + + // Set maxSessionMemory to 1MB so the leak causes errors faster. + maxSessionMemory: 1 + }); + + // Repeatedly create a new stream and read the incoming data. Even though we + // only have one stream active at a time, prior to the fix for #29223, + // session memory would steadily increase and we'd eventually hit the 1MB + // maxSessionMemory limit and get NGHTTP2_ENHANCE_YOUR_CALM errors trying to + // create new streams. + let streamsLeft = 50; + function newStream() { + const stream = client.request({ ':path': '/' }); + + stream.on('data', () => { }); + + stream.on('close', () => { + if (streamsLeft-- > 0) { + newStream(); + } else { + client.destroy(); + server.close(); + } + }); + } + + newStream(); +})); diff --git a/test/parallel/test-http2-session-settings.js b/test/parallel/test-http2-session-settings.js index 6061808082519d..29b6365ef1a3c4 100644 --- a/test/parallel/test-http2-session-settings.js +++ b/test/parallel/test-http2-session-settings.js @@ -38,6 +38,12 @@ server.on( }) ); +server.on('session', (session) => { + session.settings({ + maxConcurrentStreams: 2 + }); +}); + server.listen( 0, common.mustCall(() => { @@ -57,11 +63,18 @@ server.listen( assert.strictEqual(settings.maxFrameSize, 16384); }, 2) ); + + let calledOnce = false; client.on( 'remoteSettings', common.mustCall((settings) => { assert(settings); - }) + assert.strictEqual( + settings.maxConcurrentStreams, + calledOnce ? 2 : (2 ** 32) - 1 + ); + calledOnce = true; + }, 2) ); const headers = { ':path': '/' }; diff --git a/test/parallel/test-readable-large-hwm.js b/test/parallel/test-readable-large-hwm.js new file mode 100644 index 00000000000000..d5bf25bc0e61c1 --- /dev/null +++ b/test/parallel/test-readable-large-hwm.js @@ -0,0 +1,27 @@ +'use strict'; +const common = require('../common'); +const { Readable } = require('stream'); + +// Make sure that readable completes +// even when reading larger buffer. +const bufferSize = 10 * 1024 * 1024; +let n = 0; +const r = new Readable({ + read() { + // Try to fill readable buffer piece by piece. + r.push(Buffer.alloc(bufferSize / 10)); + + if (n++ > 10) { + r.push(null); + } + } +}); + +r.on('readable', () => { + while (true) { + const ret = r.read(bufferSize); + if (ret === null) + break; + } +}); +r.on('end', common.mustCall()); diff --git a/tools/getarch.py b/tools/getarch.py new file mode 100644 index 00000000000000..3c366525463340 --- /dev/null +++ b/tools/getarch.py @@ -0,0 +1,10 @@ +from __future__ import print_function +from utils import GuessArchitecture +arch = GuessArchitecture() + +# assume 64 bit unless set specifically +print(GuessArchitecture() \ + .replace('ia32', 'x64') \ + .replace('ppc', 'ppc64') \ + .replace('arm', 'arm64') \ + .replace('s390', 's390x')) diff --git a/tools/getendian.py b/tools/getendian.py new file mode 100644 index 00000000000000..0f9fcc1c860584 --- /dev/null +++ b/tools/getendian.py @@ -0,0 +1,4 @@ +from __future__ import print_function +import sys +# "little" or "big" +print(sys.byteorder) diff --git a/tools/getmachine.py b/tools/getmachine.py new file mode 100644 index 00000000000000..046d8b17a797fd --- /dev/null +++ b/tools/getmachine.py @@ -0,0 +1,3 @@ +from __future__ import print_function +import platform +print(platform.machine()) diff --git a/tools/getnodeversion.py b/tools/getnodeversion.py index 59f8aabe49eceb..c9f82160c0f386 100644 --- a/tools/getnodeversion.py +++ b/tools/getnodeversion.py @@ -1,3 +1,4 @@ +from __future__ import print_function import os import re diff --git a/tools/make-v8.sh b/tools/make-v8.sh index fd66fda94274df..1a6e175b6158cc 100755 --- a/tools/make-v8.sh +++ b/tools/make-v8.sh @@ -12,7 +12,9 @@ if [[ "$ARCH" == "s390x" ]] || [[ "$ARCH" == "ppc64le" ]]; then export BUILD_TOOLS=/home/iojs/build-tools export LD_LIBRARY_PATH=$BUILD_TOOLS:$LD_LIBRARY_PATH export PATH=$BUILD_TOOLS:$PATH - CXX_PATH=`which $CXX |grep g++` + if [[ X"$CXX" != X ]]; then + CXX_PATH=`which $CXX |grep g++` + fi rm -f "$BUILD_TOOLS/g++" rm -f "$BUILD_TOOLS/gcc" fi @@ -24,8 +26,10 @@ if [[ "$ARCH" == "s390x" ]]; then gn gen -v out.gn/$BUILD_ARCH_TYPE --args='is_component_build=false is_debug=false use_goma=false goma_dir="None" use_custom_libcxx=false v8_target_cpu="s390x" target_cpu="s390x"' ninja -v -C out.gn/$BUILD_ARCH_TYPE d8 cctest inspector-test elif [[ "$ARCH" == "ppc64le" ]]; then - ln -s /usr/bin/$CXX "$BUILD_TOOLS/g++" - ln -s /usr/bin/$CC "$BUILD_TOOLS/gcc" + if [[ X"$CXX" != X ]]; then + ln -s /usr/bin/$CXX "$BUILD_TOOLS/g++" + ln -s /usr/bin/$CC "$BUILD_TOOLS/gcc" + fi g++ --version export PKG_CONFIG_PATH=$BUILD_TOOLS/pkg-config-files gn gen out.gn/$BUILD_ARCH_TYPE --args='is_component_build=false is_debug=false use_goma=false goma_dir="None" use_custom_libcxx=false v8_target_cpu="ppc64" target_cpu="ppc64"' diff --git a/tools/test.py b/tools/test.py index 3ddbb64a91e3d7..1f0a037b47c6e8 100755 --- a/tools/test.py +++ b/tools/test.py @@ -1184,6 +1184,9 @@ def ClassifyTests(self, cases, env): outcomes = reduce(set.union, outcomes_list, set()) unused_rules.difference_update(matches) case.outcomes = set(outcomes) or set([PASS]) + # slow tests may also just pass. + if SLOW in case.outcomes: + case.outcomes.add(PASS) result.append(case) return result, unused_rules diff --git a/vcbuild.bat b/vcbuild.bat index 26c6b26dee69c0..c7c156e9b41d2d 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -68,7 +68,8 @@ set no_cctest= set cctest= set openssl_no_asm= set doc= -set extra_msbuild_args=^ +set extra_msbuild_args= +set exit_code=0 :next-arg if "%1"=="" goto args-done @@ -559,9 +560,11 @@ if defined no_cctest echo Skipping cctest because no-cctest was specified && got if not exist "%config%\cctest.exe" echo cctest.exe not found. Run "vcbuild test" or "vcbuild cctest" to build it. && goto run-test-py echo running 'cctest %cctest_args%' "%config%\cctest" %cctest_args% +if %errorlevel% neq 0 set exit_code=%errorlevel% :run-test-py echo running 'python tools\test.py %test_args%' python tools\test.py %test_args% +if %errorlevel% neq 0 set exit_code=%errorlevel% goto test-v8 :test-v8 @@ -672,7 +675,7 @@ echo vcbuild.bat no-cctest : skip building cctest.exe goto exit :exit -goto :EOF +exit /b %exit_code% rem ***************