From 4299e976ec4a7c4d1a21ad77c442e7ac82db3f93 Mon Sep 17 00:00:00 2001 From: William Armiros <54150514+willarmiros@users.noreply.github.com> Date: Tue, 14 Apr 2020 11:01:58 -0500 Subject: [PATCH 1/6] doc: corrected ERR_SOCKET_CANNOT_SEND message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/32847 Reviewed-By: Colin Ihrig Reviewed-By: Rich Trott Reviewed-By: Ruben Bridgewater Reviewed-By: Juan José Arboleda --- doc/api/errors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/errors.md b/doc/api/errors.md index 8f3af6fcb6a9d6..32917dc20a7fc9 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -2310,7 +2310,7 @@ added: v9.0.0 removed: REPLACEME --> -Data could be sent on a socket. +Data could not be sent on a socket. ### `ERR_STDERR_CLOSE` From 10cc254790bea4dbad5572eb0eef25b43061f440 Mon Sep 17 00:00:00 2001 From: Matt Kulukundis Date: Thu, 16 Apr 2020 19:30:08 -0400 Subject: [PATCH 2/6] src: fix null deref in AllocatedBuffer::clear MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An empty buffer can have a null environment. Previously, we were getting away with with this, but -fsanitize=null in clang caught it. PR-URL: https://github.com/nodejs/node/pull/32892 Reviewed-By: Anna Henningsen Reviewed-By: David Carlier Reviewed-By: Jan Krems Reviewed-By: James M Snell Reviewed-By: Juan José Arboleda --- src/env-inl.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/env-inl.h b/src/env-inl.h index f681a0bf1d8dcc..cab967f10db530 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -1003,7 +1003,10 @@ inline AllocatedBuffer::~AllocatedBuffer() { inline void AllocatedBuffer::clear() { uv_buf_t buf = release(); - env_->Free(buf.base, buf.len); + if (buf.base != nullptr) { + CHECK_NOT_NULL(env_); + env_->Free(buf.base, buf.len); + } } // It's a bit awkward to define this Buffer::New() overload here, but it From 372c7cc3c271c9c3a15118c669e7f72b9c5ea103 Mon Sep 17 00:00:00 2001 From: Beth Griggs Date: Tue, 10 Mar 2020 17:16:08 +0000 Subject: [PATCH 3/6] 2020-04-21, Version 14.0.0 (Current) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deprecations: - (SEMVER-MAJOR) crypto: move pbkdf2 without digest to EOL (James M Snell) [#31166](https://github.com/nodejs/node/pull/31166) - (SEMVER-MAJOR) fs: deprecate closing FileHandle on garbage collection (James M Snell) [#28396](https://github.com/nodejs/node/pull/28396) - (SEMVER-MAJOR) http: move OutboundMessage.prototype.flush to EOL (James M Snell) [#31164](https://github.com/nodejs/node/pull/31164) - (SEMVER-MAJOR) lib: move GLOBAL and root aliases to EOL (James M Snell) [#31167](https://github.com/nodejs/node/pull/31167) - (SEMVER-MAJOR) os: move tmpDir() to EOL (James M Snell)[#31169](https://github.com/nodejs/node/pull/31169) - (SEMVER-MAJOR) src: remove deprecated wasm type check (Clemens Backes) [#32116](https://github.com/nodejs/node/pull/32116) - (SEMVER-MAJOR) stream: move \_writableState.buffer to EOL (James M Snell) [#31165](https://github.com/nodejs/node/pull/31165) - (SEMVER-MINOR) doc: deprecate process.mainModule (Antoine du HAMEL) [#32232](https://github.com/nodejs/node/pull/32232) - (SEMVER-MINOR) doc: deprecate process.umask() with no arguments (Colin Ihrig) [#32499](https://github.com/nodejs/node/pull/32499) ECMAScript Modules - Experimental Warning Removal: - module: remove experimental modules warning (Guy Bedford) [#31974](https://github.com/nodejs/node/pull/31974) In Node.js 13 we removed the need to include the --experimental-modules flag, but when running EcmaScript Modules in Node.js, this would still result in a warning ExperimentalWarning: The ESM module loader is experimental. As of Node.js 14 there is no longer this warning when using ESM in Node.js. However, the ESM implementation in Node.js remains experimental. As per our stability index: “The feature is not subject to Semantic Versioning rules. Non-backward compatible changes or removal may occur in any future release.” Users should be cautious when using the feature in production environments. Please keep in mind that the implementation of ESM in Node.js differs from the developer experience you might be familiar with. Most transpilation workflows support features such as optional file extensions or JSON modules that the Node.js ESM implementation does not support. It is highly likely that modules from transpiled environments will require a certain degree of refactoring to work in Node.js. It is worth mentioning that many of our design decisions were made with two primary goals. Spec compliance and Web Compatibility. It is our belief that the current implementation offers a future proof model to authoring ESM modules that paves the path to Universal JavaScript. Please read more in our documentation. The ESM implementation in Node.js is still experimental but we do believe that we are getting very close to being able to call ESM in Node.js “stable”. Removing the warning is a huge step in that direction. New V8 ArrayBuffer API: * **src**: migrate to new V8 ArrayBuffer API (Thang Tran) [#30782](https://github.com/nodejs/node/pull/30782) Multiple ArrayBuffers pointing to the same base address are no longer allowed by V8. This may impact native addons. Toolchain and Compiler Upgrades: - (SEMVER-MAJOR) build: update macos deployment target to 10.13 for 14.x (AshCripps)[#32454](https://github.com/nodejs/node/pull/32454) - (SEMVER-MAJOR) doc: update cross compiler machine for Linux armv7 (Richard Lau) [#32812](https://github.com/nodejs/node/pull/32812) - (SEMVER-MAJOR) doc: update Centos/RHEL releases use devtoolset-8 (Richard Lau) [#32812](https://github.com/nodejs/node/pull/32812) - (SEMVER-MAJOR) doc: remove SmartOS from official binaries (Richard Lau) [#32812](https://github.com/nodejs/node/pull/32812) - (SEMVER-MAJOR) win: block running on EOL Windows versions (João Reis) [#31954](https://github.com/nodejs/node/pull/31954) It is expected that there will be an ABI mismatch on ARM between the Node.js binary and native addons. Native addons are only broken if they interact with `std::shared_ptr`. This is expected to be fixed in a later version of Node.js 14. - [#30786](https://github.com/nodejs/node/issues/30786) Update to V8 8.1: - (SEMVER-MAJOR) deps: update V8 to 8.1.307.20 (Matheus Marchini) [#32116](https://github.com/nodejs/node/pull/32116) Other Notable Changes: - cli, report: move --report-on-fatalerror to stable (Colin Ihrig) [#32496](https://github.com/nodejs/node/pull/32496) - deps: upgrade to libuv 1.37.0 (Colin Ihrig) [#32866](https://github.com/nodejs/node/pull/32866) - fs: add fs/promises alias module (Gus Caplan) [#31553](https://github.com/nodejs/node/pull/31553) PR-URL: https://github.com/nodejs/node/pull/32181 --- CHANGELOG.md | 7 +- doc/api/assert.md | 8 +- doc/api/child_process.md | 2 +- doc/api/cli.md | 2 +- doc/api/crypto.md | 4 +- doc/api/deprecations.md | 16 +- doc/api/embedding.md | 2 +- doc/api/errors.md | 2 +- doc/api/fs.md | 20 +- doc/api/process.md | 6 +- doc/api/stream.md | 6 +- doc/api/util.md | 2 +- doc/changelogs/CHANGELOG_ARCHIVE.md | 2 + doc/changelogs/CHANGELOG_IOJS.md | 1 + doc/changelogs/CHANGELOG_V010.md | 1 + doc/changelogs/CHANGELOG_V012.md | 1 + doc/changelogs/CHANGELOG_V10.md | 1 + doc/changelogs/CHANGELOG_V11.md | 1 + doc/changelogs/CHANGELOG_V12.md | 1 + doc/changelogs/CHANGELOG_V13.md | 1 + doc/changelogs/CHANGELOG_V14.md | 311 ++++++++++++++++++++++++++++ doc/changelogs/CHANGELOG_V4.md | 1 + doc/changelogs/CHANGELOG_V5.md | 1 + doc/changelogs/CHANGELOG_V6.md | 1 + doc/changelogs/CHANGELOG_V7.md | 1 + doc/changelogs/CHANGELOG_V8.md | 1 + doc/changelogs/CHANGELOG_V9.md | 1 + src/node_version.h | 2 +- 28 files changed, 368 insertions(+), 37 deletions(-) create mode 100644 doc/changelogs/CHANGELOG_V14.md diff --git a/CHANGELOG.md b/CHANGELOG.md index dfab02ecf435c0..a4862ff612f275 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ Select a Node.js version below to view the changelog history: +* [Node.js 14](doc/changelogs/CHANGELOG_V14.md) **Current** * [Node.js 13](doc/changelogs/CHANGELOG_V13.md) **Current** * [Node.js 12](doc/changelogs/CHANGELOG_V12.md) **Long Term Support** * [Node.js 11](doc/changelogs/CHANGELOG_V11.md) End-of-Life @@ -23,12 +24,16 @@ release. + +
14Current 13Current 12LTS 10LTS
+14.0.0
+
13.13.0
13.12.0
13.11.0
@@ -48,7 +53,7 @@ release.
12.16.2
-12.16.1<
+12.16.1
12.16.0
12.15.0
12.14.1
diff --git a/doc/api/assert.md b/doc/api/assert.md index 732b4ba8e02d97..d5d0a606c2bf46 100644 --- a/doc/api/assert.md +++ b/doc/api/assert.md @@ -161,7 +161,7 @@ An alias of [`assert.ok()`][]. diff --git a/doc/api/cli.md b/doc/api/cli.md index c59c266c387711..b56a77143863d4 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -648,7 +648,7 @@ Name of the file to which the report will be written. @@ -2621,7 +2621,7 @@ async function openAndClose() { ### DEP0138: `process.mainModule` @@ -2639,7 +2639,7 @@ purpose and is only available on CommonJS environment. ### DEP0139: `process.umask()` with no arguments diff --git a/doc/api/embedding.md b/doc/api/embedding.md index 7db24b325ec7ef..9eaa144e3da578 100644 --- a/doc/api/embedding.md +++ b/doc/api/embedding.md @@ -1,6 +1,6 @@ # C++ Embedder API - + Node.js provides a number of C++ APIs that can be used to execute JavaScript in a Node.js environment from other C++ software. diff --git a/doc/api/errors.md b/doc/api/errors.md index 32917dc20a7fc9..5308490b88fe8c 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -2307,7 +2307,7 @@ The `repl` module was unable to parse data from the REPL history file. ### `ERR_SOCKET_CANNOT_SEND` Data could not be sent on a socket. diff --git a/doc/api/fs.md b/doc/api/fs.md index f8db729ca69ffa..4e11fd32a04cb8 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -3997,7 +3997,7 @@ This happens when: @@ -1499,7 +1499,7 @@ debugger. See [Signal Events][]. ## `process.mainModule` > Stability: 0 - Deprecated: Use [`require.main`][] instead. @@ -2427,7 +2427,7 @@ flag's behavior. @@ -2076,7 +2076,7 @@ changes: pr-url: https://github.com/nodejs/node/pull/22795 description: Add `autoDestroy` option to automatically `destroy()` the stream when it emits `'end'` or errors. - - version: REPLACEME + - version: v14.0.0 pr-url: https://github.com/nodejs/node/pull/30623 description: Change `autoDestroy` option default to `true`. --> diff --git a/doc/api/util.md b/doc/api/util.md index 0f04d7bd179b97..02453e75c34075 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -1897,7 +1897,7 @@ util.types.isWeakSet(new WeakSet()); // Returns true ### `util.types.isWebAssemblyCompiledModule(value)` > Stability: 0 - Deprecated: Use `value instanceof WebAssembly.Module` instead. diff --git a/doc/changelogs/CHANGELOG_ARCHIVE.md b/doc/changelogs/CHANGELOG_ARCHIVE.md index cce728d7172cee..ff94c455586e34 100644 --- a/doc/changelogs/CHANGELOG_ARCHIVE.md +++ b/doc/changelogs/CHANGELOG_ARCHIVE.md @@ -154,6 +154,8 @@
* Other Versions + * [14.x](CHANGELOG_V14.md) + * [13.x](CHANGELOG_V13.md) * [12.x](CHANGELOG_V12.md) * [11.x](CHANGELOG_V11.md) * [10.x](CHANGELOG_V10.md) diff --git a/doc/changelogs/CHANGELOG_IOJS.md b/doc/changelogs/CHANGELOG_IOJS.md index fceeac2d5fcd0a..e736a70dedfef2 100644 --- a/doc/changelogs/CHANGELOG_IOJS.md +++ b/doc/changelogs/CHANGELOG_IOJS.md @@ -63,6 +63,7 @@ * Other Versions + * [14.x](CHANGELOG_V14.md) * [13.x](CHANGELOG_V13.md) * [12.x](CHANGELOG_V12.md) * [11.x](CHANGELOG_V11.md) diff --git a/doc/changelogs/CHANGELOG_V010.md b/doc/changelogs/CHANGELOG_V010.md index abd67467fc1296..65b6bef55bbd20 100644 --- a/doc/changelogs/CHANGELOG_V010.md +++ b/doc/changelogs/CHANGELOG_V010.md @@ -65,6 +65,7 @@ * Other Versions + * [14.x](CHANGELOG_V14.md) * [13.x](CHANGELOG_V13.md) * [12.x](CHANGELOG_V12.md) * [11.x](CHANGELOG_V11.md) diff --git a/doc/changelogs/CHANGELOG_V012.md b/doc/changelogs/CHANGELOG_V012.md index 38a185f5e16d02..8a5ebf3e429fa6 100644 --- a/doc/changelogs/CHANGELOG_V012.md +++ b/doc/changelogs/CHANGELOG_V012.md @@ -33,6 +33,7 @@ * Other Versions + * [14.x](CHANGELOG_V14.md) * [13.x](CHANGELOG_V13.md) * [12.x](CHANGELOG_V12.md) * [11.x](CHANGELOG_V11.md) diff --git a/doc/changelogs/CHANGELOG_V10.md b/doc/changelogs/CHANGELOG_V10.md index 7a0e71b0ae215b..e347b51619e6d8 100644 --- a/doc/changelogs/CHANGELOG_V10.md +++ b/doc/changelogs/CHANGELOG_V10.md @@ -50,6 +50,7 @@ * Other Versions + * [14.x](CHANGELOG_V14.md) * [13.x](CHANGELOG_V13.md) * [12.x](CHANGELOG_V12.md) * [11.x](CHANGELOG_V11.md) diff --git a/doc/changelogs/CHANGELOG_V11.md b/doc/changelogs/CHANGELOG_V11.md index b0f6d833da6a64..960276df5e0293 100644 --- a/doc/changelogs/CHANGELOG_V11.md +++ b/doc/changelogs/CHANGELOG_V11.md @@ -31,6 +31,7 @@ * Other Versions + * [14.x](CHANGELOG_V14.md) * [13.x](CHANGELOG_V13.md) * [12.x](CHANGELOG_V12.md) * [10.x](CHANGELOG_V10.md) diff --git a/doc/changelogs/CHANGELOG_V12.md b/doc/changelogs/CHANGELOG_V12.md index bf8bfa246ad327..28e0c6ec306316 100644 --- a/doc/changelogs/CHANGELOG_V12.md +++ b/doc/changelogs/CHANGELOG_V12.md @@ -42,6 +42,7 @@ * Other Versions + * [14.x](CHANGELOG_V14.md) * [13.x](CHANGELOG_V13.md) * [11.x](CHANGELOG_V11.md) * [10.x](CHANGELOG_V10.md) diff --git a/doc/changelogs/CHANGELOG_V13.md b/doc/changelogs/CHANGELOG_V13.md index 719a58809fd773..3c2d64e2d960ee 100644 --- a/doc/changelogs/CHANGELOG_V13.md +++ b/doc/changelogs/CHANGELOG_V13.md @@ -30,6 +30,7 @@ * Other Versions + * [14.x](CHANGELOG_V14.md) * [12.x](CHANGELOG_V12.md) * [11.x](CHANGELOG_V11.md) * [10.x](CHANGELOG_V10.md) diff --git a/doc/changelogs/CHANGELOG_V14.md b/doc/changelogs/CHANGELOG_V14.md new file mode 100644 index 00000000000000..37a678820fcdd7 --- /dev/null +++ b/doc/changelogs/CHANGELOG_V14.md @@ -0,0 +1,311 @@ +# Node.js 14 ChangeLog + + + + + + + + + + + +
Current
+14.0.0
+
+ +* Other Versions + * [13.x](CHANGELOG_V13.md) + * [12.x](CHANGELOG_V12.md) + * [11.x](CHANGELOG_V11.md) + * [10.x](CHANGELOG_V10.md) + * [9.x](CHANGELOG_V9.md) + * [8.x](CHANGELOG_V8.md) + * [7.x](CHANGELOG_V7.md) + * [6.x](CHANGELOG_V6.md) + * [5.x](CHANGELOG_V5.md) + * [4.x](CHANGELOG_V4.md) + * [0.12.x](CHANGELOG_V012.md) + * [0.10.x](CHANGELOG_V010.md) + * [io.js](CHANGELOG_IOJS.md) + * [Archive](CHANGELOG_ARCHIVE.md) + + +## 2020-04-21, Version 14.0.0 (Current), @BethGriggs + +### Notable Changes + +#### Deprecations + +* **(SEMVER-MAJOR)** **crypto**: move pbkdf2 without digest to EOL (James M Snell) [#31166](https://github.com/nodejs/node/pull/31166) +* **(SEMVER-MAJOR)** **fs**: deprecate closing FileHandle on garbage collection (James M Snell) [#28396](https://github.com/nodejs/node/pull/28396) +* **(SEMVER-MAJOR)** **http**: move OutboundMessage.prototype.flush to EOL (James M Snell) [#31164](https://github.com/nodejs/node/pull/31164) +* **(SEMVER-MAJOR)** **lib**: move GLOBAL and root aliases to EOL (James M Snell) [#31167](https://github.com/nodejs/node/pull/31167) +* **(SEMVER-MAJOR)** **os**: move tmpDir() to EOL (James M Snell) [#31169](https://github.com/nodejs/node/pull/31169) +* **(SEMVER-MAJOR)** **src**: remove deprecated wasm type check (Clemens Backes) [#32116](https://github.com/nodejs/node/pull/32116) +* **(SEMVER-MAJOR)** **stream**: move \_writableState.buffer to EOL (James M Snell) [#31165](https://github.com/nodejs/node/pull/31165) +* **(SEMVER-MINOR)** **doc**: deprecate process.mainModule (Antoine du HAMEL) [#32232](https://github.com/nodejs/node/pull/32232) +* **(SEMVER-MINOR)** **doc**: deprecate process.umask() with no arguments (Colin Ihrig) [#32499](https://github.com/nodejs/node/pull/32499) + +#### ECMAScript Modules - Experimental Warning Removal + +* **module**: remove experimental modules warning (Guy Bedford) [#31974](https://github.com/nodejs/node/pull/31974) + +In Node.js 13 we removed the need to include the --experimental-modules flag, but when running EcmaScript Modules in Node.js, this would still result in a warning ExperimentalWarning: The ESM module loader is experimental. + +As of Node.js 14 there is no longer this warning when using ESM in Node.js. However, the ESM implementation in Node.js remains experimental. As per our stability index: “The feature is not subject to Semantic Versioning rules. Non-backward compatible changes or removal may occur in any future release.” Users should be cautious when using the feature in production environments. + +Please keep in mind that the implementation of ESM in Node.js differs from the developer experience you might be familiar with. Most transpilation workflows support features such as optional file extensions or JSON modules that the Node.js ESM implementation does not support. It is highly likely that modules from transpiled environments will require a certain degree of refactoring to work in Node.js. It is worth mentioning that many of our design decisions were made with two primary goals. Spec compliance and Web Compatibility. It is our belief that the current implementation offers a future proof model to authoring ESM modules that paves the path to Universal JavaScript. Please read more in our documentation. + +The ESM implementation in Node.js is still experimental but we do believe that we are getting very close to being able to call ESM in Node.js “stable”. Removing the warning is a huge step in that direction. + +#### New V8 ArrayBuffer API + +* **src**: migrate to new V8 ArrayBuffer API (Thang Tran) [#30782](https://github.com/nodejs/node/pull/30782) + +Multiple ArrayBuffers pointing to the same base address are no longer allowed by V8. This may impact native addons. + +#### Toolchain and Compiler Upgrades + +* **(SEMVER-MAJOR)** **build**: update macos deployment target to 10.13 for 14.x (AshCripps) [#32454](https://github.com/nodejs/node/pull/32454) +* **(SEMVER-MAJOR)** **doc**: update cross compiler machine for Linux armv7 (Richard Lau) [#32812](https://github.com/nodejs/node/pull/32812) +* **(SEMVER-MAJOR)** **doc**: update Centos/RHEL releases use devtoolset-8 (Richard Lau) [#32812](https://github.com/nodejs/node/pull/32812) +* **(SEMVER-MAJOR)** **doc**: remove SmartOS from official binaries (Richard Lau) [#32812](https://github.com/nodejs/node/pull/32812) +* **(SEMVER-MAJOR)** **win**: block running on EOL Windows versions (João Reis) [#31954](https://github.com/nodejs/node/pull/31954) + +It is expected that there will be an ABI mismatch on ARM between the Node.js binary and native addons. Native addons are only broken if they +interact with `std::shared_ptr`. This is expected to be fixed in a later version of Node.js 14. - [#30786](https://github.com/nodejs/node/issues/30786) + +#### Update to V8 8.1 + +* **(SEMVER-MAJOR)** **deps**: update V8 to 8.1.307.20 (Matheus Marchini) [#32116](https://github.com/nodejs/node/pull/32116) + +#### Other Notable Changes: + +* **cli, report**: move --report-on-fatalerror to stable (Colin Ihrig) [#32496](https://github.com/nodejs/node/pull/32496) +* **deps**: upgrade to libuv 1.37.0 (Colin Ihrig) [#32866](https://github.com/nodejs/node/pull/32866) +* **fs**: add fs/promises alias module (Gus Caplan) [#31553](https://github.com/nodejs/node/pull/31553) + +### Semver-Major Commits + +* [[`5360dd151d`](https://github.com/nodejs/node/commit/5360dd151d)] - **(SEMVER-MAJOR)** **assert**: handle (deep) equal(NaN, NaN) as being identical (Ruben Bridgewater) [#30766](https://github.com/nodejs/node/pull/30766) +* [[`a621608f12`](https://github.com/nodejs/node/commit/a621608f12)] - **(SEMVER-MAJOR)** **build**: update macos deployment target to 10.13 for 14.x (AshCripps) [#32454](https://github.com/nodejs/node/pull/32454) +* [[`e65bed1b7e`](https://github.com/nodejs/node/commit/e65bed1b7e)] - **(SEMVER-MAJOR)** **child_process**: create proper public API for `channel` (Anna Henningsen) [#30165](https://github.com/nodejs/node/pull/30165) +* [[`1b9a62cff4`](https://github.com/nodejs/node/commit/1b9a62cff4)] - **(SEMVER-MAJOR)** **crypto**: make DH error messages consistent (Tobias Nießen) [#31873](https://github.com/nodejs/node/pull/31873) +* [[`bffa5044c5`](https://github.com/nodejs/node/commit/bffa5044c5)] - **(SEMVER-MAJOR)** **crypto**: move pbkdf2 without digest to EOL (James M Snell) [#31166](https://github.com/nodejs/node/pull/31166) +* [[`10f5fa7513`](https://github.com/nodejs/node/commit/10f5fa7513)] - **(SEMVER-MAJOR)** **crypto**: forbid setting the PBKDF2 iter count to 0 (Tobias Nießen) [#30578](https://github.com/nodejs/node/pull/30578) +* [[`2883c855e0`](https://github.com/nodejs/node/commit/2883c855e0)] - **(SEMVER-MAJOR)** **deps**: update V8 to 8.1.307.20 (Matheus Marchini) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`1b2e2944bc`](https://github.com/nodejs/node/commit/1b2e2944bc)] - **(SEMVER-MAJOR)** **dgram**: don't hide implicit bind errors (Colin Ihrig) [#31958](https://github.com/nodejs/node/pull/31958) +* [[`1a1ce93317`](https://github.com/nodejs/node/commit/1a1ce93317)] - **(SEMVER-MAJOR)** **doc**: update cross compiler machine for Linux armv7 (Richard Lau) [#32812](https://github.com/nodejs/node/pull/32812) +* [[`dad96e4fc1`](https://github.com/nodejs/node/commit/dad96e4fc1)] - **(SEMVER-MAJOR)** **doc**: update Centos/RHEL releases use devtoolset-8 (Richard Lau) [#32812](https://github.com/nodejs/node/pull/32812) +* [[`5317202aa1`](https://github.com/nodejs/node/commit/5317202aa1)] - **(SEMVER-MAJOR)** **doc**: remove SmartOS from official binaries (Richard Lau) [#32812](https://github.com/nodejs/node/pull/32812) +* [[`75ee5b2622`](https://github.com/nodejs/node/commit/75ee5b2622)] - **(SEMVER-MAJOR)** **doc**: deprecate process.umask() with no arguments (Colin Ihrig) [#32499](https://github.com/nodejs/node/pull/32499) +* [[`afe353061b`](https://github.com/nodejs/node/commit/afe353061b)] - **(SEMVER-MAJOR)** **doc**: fs.write is not longer coercing strings (Juan José Arboleda) [#31030](https://github.com/nodejs/node/pull/31030) +* [[`a45c1aa39f`](https://github.com/nodejs/node/commit/a45c1aa39f)] - **(SEMVER-MAJOR)** **doc**: fix mode and flags being mistaken in fs (Ruben Bridgewater) [#27044](https://github.com/nodejs/node/pull/27044) +* [[`331d636240`](https://github.com/nodejs/node/commit/331d636240)] - **(SEMVER-MAJOR)** **errors**: remove unused ERR\_SOCKET\_CANNOT\_SEND error (Colin Ihrig) [#31958](https://github.com/nodejs/node/pull/31958) +* [[`b8e41774d4`](https://github.com/nodejs/node/commit/b8e41774d4)] - **(SEMVER-MAJOR)** **fs**: add fs/promises alias module (Gus Caplan) [#31553](https://github.com/nodejs/node/pull/31553) +* [[`fb6df3bfac`](https://github.com/nodejs/node/commit/fb6df3bfac)] - **(SEMVER-MAJOR)** **fs**: validate the input data to be of expected types (Ruben Bridgewater) [#31030](https://github.com/nodejs/node/pull/31030) +* [[`2d8febceef`](https://github.com/nodejs/node/commit/2d8febceef)] - **(SEMVER-MAJOR)** **fs**: deprecate closing FileHandle on garbage collection (James M Snell) [#28396](https://github.com/nodejs/node/pull/28396) +* [[`67e067eb06`](https://github.com/nodejs/node/commit/67e067eb06)] - **(SEMVER-MAJOR)** **fs**: watch signals for recursive incompatibility (Eran Levin) [#29947](https://github.com/nodejs/node/pull/29947) +* [[`f0d2df41f8`](https://github.com/nodejs/node/commit/f0d2df41f8)] - **(SEMVER-MAJOR)** **fs**: change streams to always emit close by default (Robert Nagy) [#31408](https://github.com/nodejs/node/pull/31408) +* [[`a13500f503`](https://github.com/nodejs/node/commit/a13500f503)] - **(SEMVER-MAJOR)** **fs**: improve mode and flags validation (Ruben Bridgewater) [#27044](https://github.com/nodejs/node/pull/27044) +* [[`535e9571f5`](https://github.com/nodejs/node/commit/535e9571f5)] - **(SEMVER-MAJOR)** **fs**: make FSStatWatcher.start private (Lucas Holmquist) [#29971](https://github.com/nodejs/node/pull/29971) +* [[`c1b2f6afbe`](https://github.com/nodejs/node/commit/c1b2f6afbe)] - **(SEMVER-MAJOR)** **http**: detach socket from IncomingMessage on keep-alive (Robert Nagy) [#32153](https://github.com/nodejs/node/pull/32153) +* [[`173d044d09`](https://github.com/nodejs/node/commit/173d044d09)] - **(SEMVER-MAJOR)** **http**: align OutgoingMessage and ClientRequest destroy (Robert Nagy) [#32148](https://github.com/nodejs/node/pull/32148) +* [[`d3715c76b5`](https://github.com/nodejs/node/commit/d3715c76b5)] - **(SEMVER-MAJOR)** **http**: move OutboundMessage.prototype.flush to EOL (James M Snell) [#31164](https://github.com/nodejs/node/pull/31164) +* [[`c776a37791`](https://github.com/nodejs/node/commit/c776a37791)] - **(SEMVER-MAJOR)** **http**: end with data can cause write after end (Robert Nagy) [#28666](https://github.com/nodejs/node/pull/28666) +* [[`ff2ed3ec85`](https://github.com/nodejs/node/commit/ff2ed3ec85)] - **(SEMVER-MAJOR)** **http**: remove unused hasItems() from freelist (Rich Trott) [#30744](https://github.com/nodejs/node/pull/30744) +* [[`d247a8e1dc`](https://github.com/nodejs/node/commit/d247a8e1dc)] - **(SEMVER-MAJOR)** **http**: emit close on socket re-use (Robert Nagy) [#28685](https://github.com/nodejs/node/pull/28685) +* [[`6f0ec79e42`](https://github.com/nodejs/node/commit/6f0ec79e42)] - **(SEMVER-MAJOR)** **http,stream**: make virtual methods throw an error (Luigi Pinca) [#31912](https://github.com/nodejs/node/pull/31912) +* [[`ec0dd6fa1c`](https://github.com/nodejs/node/commit/ec0dd6fa1c)] - **(SEMVER-MAJOR)** **lib**: move GLOBAL and root aliases to EOL (James M Snell) [#31167](https://github.com/nodejs/node/pull/31167) +* [[`d7452b7140`](https://github.com/nodejs/node/commit/d7452b7140)] - **(SEMVER-MAJOR)** **module**: warn on using unfinished circular dependency (Anna Henningsen) [#29935](https://github.com/nodejs/node/pull/29935) +* [[`eeccd52b4e`](https://github.com/nodejs/node/commit/eeccd52b4e)] - **(SEMVER-MAJOR)** **net**: make readable/writable start as true (Robert Nagy) [#32272](https://github.com/nodejs/node/pull/32272) +* [[`ab4115f17c`](https://github.com/nodejs/node/commit/ab4115f17c)] - **(SEMVER-MAJOR)** **os**: move tmpDir() to EOL (James M Snell) [#31169](https://github.com/nodejs/node/pull/31169) +* [[`8c18e91c8a`](https://github.com/nodejs/node/commit/8c18e91c8a)] - **(SEMVER-MAJOR)** **process**: remove undocumented `now` argument from emitWarning() (Rich Trott) [#31643](https://github.com/nodejs/node/pull/31643) +* [[`84c426cb60`](https://github.com/nodejs/node/commit/84c426cb60)] - **(SEMVER-MAJOR)** **repl**: properly handle `repl.repl` (Ruben Bridgewater) [#30981](https://github.com/nodejs/node/pull/30981) +* [[`4f523c2c1a`](https://github.com/nodejs/node/commit/4f523c2c1a)] - **(SEMVER-MAJOR)** **src**: migrate to new V8 ArrayBuffer API (Thang Tran) [#30782](https://github.com/nodejs/node/pull/30782) +* [[`c712fb7cd6`](https://github.com/nodejs/node/commit/c712fb7cd6)] - **(SEMVER-MAJOR)** **src**: add abstract `IsolatePlatformDelegate` (Marcel Laverdet) [#30324](https://github.com/nodejs/node/pull/30324) +* [[`1428a92492`](https://github.com/nodejs/node/commit/1428a92492)] - **(SEMVER-MAJOR)** **stream**: make pipeline try to wait for 'close' (Robert Nagy) [#32158](https://github.com/nodejs/node/pull/32158) +* [[`388cef61e8`](https://github.com/nodejs/node/commit/388cef61e8)] - **(SEMVER-MAJOR)** **stream**: align stream.Duplex with net.Socket (Robert Nagy) [#32139](https://github.com/nodejs/node/pull/32139) +* [[`7cafd5f3a9`](https://github.com/nodejs/node/commit/7cafd5f3a9)] - **(SEMVER-MAJOR)** **stream**: fix finished w/ 'close' before 'end' (Robert Nagy) [#31545](https://github.com/nodejs/node/pull/31545) +* [[`311e12b962`](https://github.com/nodejs/node/commit/311e12b962)] - **(SEMVER-MAJOR)** **stream**: fix multiple destroy calls (Robert Nagy) [#29197](https://github.com/nodejs/node/pull/29197) +* [[`1f209129c7`](https://github.com/nodejs/node/commit/1f209129c7)] - **(SEMVER-MAJOR)** **stream**: throw invalid argument errors (Robert Nagy) [#31831](https://github.com/nodejs/node/pull/31831) +* [[`d016b9d708`](https://github.com/nodejs/node/commit/d016b9d708)] - **(SEMVER-MAJOR)** **stream**: finished callback for closed streams (Robert Nagy) [#31509](https://github.com/nodejs/node/pull/31509) +* [[`e559842188`](https://github.com/nodejs/node/commit/e559842188)] - **(SEMVER-MAJOR)** **stream**: make readable & writable computed (Robert Nagy) [#31197](https://github.com/nodejs/node/pull/31197) +* [[`907c07fa85`](https://github.com/nodejs/node/commit/907c07fa85)] - **(SEMVER-MAJOR)** **stream**: move \_writableState.buffer to EOL (James M Snell) [#31165](https://github.com/nodejs/node/pull/31165) +* [[`66f4e4edcb`](https://github.com/nodejs/node/commit/66f4e4edcb)] - **(SEMVER-MAJOR)** **stream**: do not emit 'end' after 'error' (Robert Nagy) [#31182](https://github.com/nodejs/node/pull/31182) +* [[`75b30c606c`](https://github.com/nodejs/node/commit/75b30c606c)] - **(SEMVER-MAJOR)** **stream**: emit 'error' asynchronously (Robert Nagy) [#29744](https://github.com/nodejs/node/pull/29744) +* [[`4bec6d13f9`](https://github.com/nodejs/node/commit/4bec6d13f9)] - **(SEMVER-MAJOR)** **stream**: enable autoDestroy by default (Robert Nagy) [#30623](https://github.com/nodejs/node/pull/30623) +* [[`20d009d2fd`](https://github.com/nodejs/node/commit/20d009d2fd)] - **(SEMVER-MAJOR)** **stream**: pipe should not swallow error (Robert Nagy) [#30993](https://github.com/nodejs/node/pull/30993) +* [[`67ed526ab0`](https://github.com/nodejs/node/commit/67ed526ab0)] - **(SEMVER-MAJOR)** **stream**: error state cleanup (Robert Nagy) [#30851](https://github.com/nodejs/node/pull/30851) +* [[`e902fadc5e`](https://github.com/nodejs/node/commit/e902fadc5e)] - **(SEMVER-MAJOR)** **stream**: do not throw multiple callback errors in writable (Robert Nagy) [#30614](https://github.com/nodejs/node/pull/30614) +* [[`e13a37e49d`](https://github.com/nodejs/node/commit/e13a37e49d)] - **(SEMVER-MAJOR)** **stream**: ensure finish is emitted in next tick (Robert Nagy) [#30733](https://github.com/nodejs/node/pull/30733) +* [[`9d09969f4c`](https://github.com/nodejs/node/commit/9d09969f4c)] - **(SEMVER-MAJOR)** **stream**: always invoke end callback (Robert Nagy) [#29747](https://github.com/nodejs/node/pull/29747) + +* [[`0f78dcc86d`](https://github.com/nodejs/node/commit/0f78dcc86d)] - **(SEMVER-MAJOR)** **util**: escape C1 control characters and switch to hex format (Ruben Bridgewater) [#29826](https://github.com/nodejs/node/pull/29826) +* [[`cb8898c48f`](https://github.com/nodejs/node/commit/cb8898c48f)] - **(SEMVER-MAJOR)** **win**: block running on EOL Windows versions (João Reis) [#31954](https://github.com/nodejs/node/pull/31954) +* [[`a9401439c7`](https://github.com/nodejs/node/commit/a9401439c7)] - **(SEMVER-MAJOR)** **zlib**: align with streams (Robert Nagy) [#32220](https://github.com/nodejs/node/pull/32220) + +### Semver-Minor Commits + +* [[`63f0dd1ab9`](https://github.com/nodejs/node/commit/63f0dd1ab9)] - **(SEMVER-MINOR)** **async_hooks**: merge run and exit methods (Andrey Pechkurov) [#31950](https://github.com/nodejs/node/pull/31950) +* [[`a683e87cd0`](https://github.com/nodejs/node/commit/a683e87cd0)] - **(SEMVER-MINOR)** **async_hooks**: prevent sync methods of async storage exiting outer context (Stephen Belanger) [#31950](https://github.com/nodejs/node/pull/31950) +* [[`f571b294f5`](https://github.com/nodejs/node/commit/f571b294f5)] - **(SEMVER-MINOR)** **doc**: deprecate process.mainModule (Antoine du HAMEL) [#32232](https://github.com/nodejs/node/pull/32232) +* [[`e04f599258`](https://github.com/nodejs/node/commit/e04f599258)] - **(SEMVER-MINOR)** **doc**: add basic embedding example documentation (Anna Henningsen) [#30467](https://github.com/nodejs/node/pull/30467) +* [[`e93503be83`](https://github.com/nodejs/node/commit/e93503be83)] - **(SEMVER-MINOR)** **embedding**: provide hook for custom process.exit() behaviour (Anna Henningsen) [#32531](https://github.com/nodejs/node/pull/32531) +* [[`a8cf886de7`](https://github.com/nodejs/node/commit/a8cf886de7)] - **(SEMVER-MINOR)** **src**: shutdown platform from FreePlatform() (Anna Henningsen) [#30467](https://github.com/nodejs/node/pull/30467) +* [[`0e576740dc`](https://github.com/nodejs/node/commit/0e576740dc)] - **(SEMVER-MINOR)** **src**: fix what a dispose without checking (Jichan) [#30467](https://github.com/nodejs/node/pull/30467) +* [[`887b6a143b`](https://github.com/nodejs/node/commit/887b6a143b)] - **(SEMVER-MINOR)** **src**: allow non-Node.js TracingControllers (Anna Henningsen) [#30467](https://github.com/nodejs/node/pull/30467) +* [[`7e0264d932`](https://github.com/nodejs/node/commit/7e0264d932)] - **(SEMVER-MINOR)** **src**: add ability to look up platform based on `Environment\*` (Anna Henningsen) [#30467](https://github.com/nodejs/node/pull/30467) +* [[`d7f11077f1`](https://github.com/nodejs/node/commit/d7f11077f1)] - **(SEMVER-MINOR)** **src**: make InitializeNodeWithArgs() official public API (Anna Henningsen) [#30467](https://github.com/nodejs/node/pull/30467) +* [[`821e21de8c`](https://github.com/nodejs/node/commit/821e21de8c)] - **(SEMVER-MINOR)** **src**: add unique\_ptr equivalent of CreatePlatform (Anna Henningsen) [#30467](https://github.com/nodejs/node/pull/30467) +* [[`7dead8440c`](https://github.com/nodejs/node/commit/7dead8440c)] - **(SEMVER-MINOR)** **src**: add LoadEnvironment() variant taking a string (Anna Henningsen) [#30467](https://github.com/nodejs/node/pull/30467) +* [[`c44edec4da`](https://github.com/nodejs/node/commit/c44edec4da)] - **(SEMVER-MINOR)** **src**: provide a variant of LoadEnvironment taking a callback (Anna Henningsen) [#30467](https://github.com/nodejs/node/pull/30467) +* [[`a9fb51f9be`](https://github.com/nodejs/node/commit/a9fb51f9be)] - **(SEMVER-MINOR)** **src**: align worker and main thread code with embedder API (Anna Henningsen) [#30467](https://github.com/nodejs/node/pull/30467) +* [[`084c379648`](https://github.com/nodejs/node/commit/084c379648)] - **(SEMVER-MINOR)** **src**: associate is\_main\_thread() with worker\_context() (Anna Henningsen) [#30467](https://github.com/nodejs/node/pull/30467) +* [[`64c01222d9`](https://github.com/nodejs/node/commit/64c01222d9)] - **(SEMVER-MINOR)** **src**: move worker\_context from Environment to IsolateData (Anna Henningsen) [#30467](https://github.com/nodejs/node/pull/30467) +* [[`288382a4ce`](https://github.com/nodejs/node/commit/288382a4ce)] - **(SEMVER-MINOR)** **src**: fix memory leak in CreateEnvironment when bootstrap fails (Anna Henningsen) [#30467](https://github.com/nodejs/node/pull/30467) +* [[`d7bc5816a5`](https://github.com/nodejs/node/commit/d7bc5816a5)] - **(SEMVER-MINOR)** **src**: make `FreeEnvironment()` perform all necessary cleanup (Anna Henningsen) [#30467](https://github.com/nodejs/node/pull/30467) +* [[`43d32b073f`](https://github.com/nodejs/node/commit/43d32b073f)] - **(SEMVER-MINOR)** **src,test**: add full-featured embedder API test (Anna Henningsen) [#30467](https://github.com/nodejs/node/pull/30467) +* [[`2061c33670`](https://github.com/nodejs/node/commit/2061c33670)] - **(SEMVER-MINOR)** **test**: add extended embedder cctest (Anna Henningsen) [#30467](https://github.com/nodejs/node/pull/30467) +* [[`2561484dcb`](https://github.com/nodejs/node/commit/2561484dcb)] - **(SEMVER-MINOR)** **test**: re-enable cctest that was commented out (Anna Henningsen) [#30467](https://github.com/nodejs/node/pull/30467) + +### Semver-Patch Commits + +* [[`9b6e797379`](https://github.com/nodejs/node/commit/9b6e797379)] - ***Revert*** "**assert**: fix line number calculation after V8 upgrade" (Michaël Zasso) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`c740fbda9d`](https://github.com/nodejs/node/commit/c740fbda9d)] - **buffer**: add type check in bidirectionalIndexOf (Gerhard Stoebich) [#32770](https://github.com/nodejs/node/pull/32770) +* [[`c8e3470e53`](https://github.com/nodejs/node/commit/c8e3470e53)] - **buffer**: mark pool ArrayBuffer as untransferable (Anna Henningsen) [#32759](https://github.com/nodejs/node/pull/32759) +* [[`f2c22db580`](https://github.com/nodejs/node/commit/f2c22db580)] - **build**: remove .git folders when testing V8 (Richard Lau) [#32877](https://github.com/nodejs/node/pull/32877) +* [[`c0f43bfda8`](https://github.com/nodejs/node/commit/c0f43bfda8)] - **build**: add configure flag to build V8 with DCHECKs (Anna Henningsen) [#32787](https://github.com/nodejs/node/pull/32787) +* [[`99e7f878ce`](https://github.com/nodejs/node/commit/99e7f878ce)] - **build**: re-enable ASAN Action using clang (Matheus Marchini) [#32776](https://github.com/nodejs/node/pull/32776) +* [[`3e55284e9b`](https://github.com/nodejs/node/commit/3e55284e9b)] - **build**: use same flags as V8 for ASAN (Matheus Marchini) [#32776](https://github.com/nodejs/node/pull/32776) +* [[`4e5ec41024`](https://github.com/nodejs/node/commit/4e5ec41024)] - **build**: add build from tarball (John Kleinschmidt) [#32129](https://github.com/nodejs/node/pull/32129) +* [[`6a349019da`](https://github.com/nodejs/node/commit/6a349019da)] - **build**: temporarily skip ASAN build (Matheus Marchini) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`da92f15413`](https://github.com/nodejs/node/commit/da92f15413)] - **build**: reset embedder string to "-node.0" (Matheus Marchini) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`e883059c24`](https://github.com/nodejs/node/commit/e883059c24)] - **cli, report**: move --report-on-fatalerror to stable (Colin Ihrig) [#32496](https://github.com/nodejs/node/pull/32496) +* [[`bf86f55e22`](https://github.com/nodejs/node/commit/bf86f55e22)] - **deps**: patch V8 to 8.1.307.30 (Michaël Zasso) [#32693](https://github.com/nodejs/node/pull/32693) +* [[`b5bbde8cf1`](https://github.com/nodejs/node/commit/b5bbde8cf1)] - **deps**: upgrade to libuv 1.37.0 (Colin Ihrig) [#32866](https://github.com/nodejs/node/pull/32866) +* [[`7afe24dba6`](https://github.com/nodejs/node/commit/7afe24dba6)] - **deps**: upgrade to libuv 1.36.0 (Colin Ihrig) [#32866](https://github.com/nodejs/node/pull/32866) +* [[`1cd235d1a0`](https://github.com/nodejs/node/commit/1cd235d1a0)] - **deps**: patch V8 to run on Xcode 8 (Matheus Marchini) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`5d867badd0`](https://github.com/nodejs/node/commit/5d867badd0)] - **deps**: V8: silence irrelevant warnings (Michaël Zasso) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`8d2c441e4d`](https://github.com/nodejs/node/commit/8d2c441e4d)] - **deps**: V8: cherry-pick 931bdbd76f5b (Matheus Marchini) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`049160dfb6`](https://github.com/nodejs/node/commit/049160dfb6)] - **deps**: V8: cherry-pick 1e36e21acc40 (Matheus Marchini) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`0220c298c5`](https://github.com/nodejs/node/commit/0220c298c5)] - **deps**: bump minimum icu version to 65 (Michaël Zasso) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`f90eba1d91`](https://github.com/nodejs/node/commit/f90eba1d91)] - **deps**: make v8.h compatible with VS2015 (Joao Reis) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`56b6a4f732`](https://github.com/nodejs/node/commit/56b6a4f732)] - **deps**: V8: forward declaration of `Rtl\*FunctionTable` (Refael Ackermann) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`40c9419b35`](https://github.com/nodejs/node/commit/40c9419b35)] - **deps**: V8: patch register-arm64.h (Refael Ackermann) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`55407ab73e`](https://github.com/nodejs/node/commit/55407ab73e)] - **deps**: patch V8 to run on older XCode versions (Ujjwal Sharma) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`990bc9adb4`](https://github.com/nodejs/node/commit/990bc9adb4)] - **deps**: V8: un-cherry-pick bd019bd (Refael Ackermann) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`17a6def4e8`](https://github.com/nodejs/node/commit/17a6def4e8)] - **deps**: update V8 dtrace & postmortem metadata (Colin Ihrig) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`0f14123186`](https://github.com/nodejs/node/commit/0f14123186)] - **deps**: V8: stub backport fast API call changes (Anna Henningsen) [#32885](https://github.com/nodejs/node/pull/32885) +* [[`bf412ed77b`](https://github.com/nodejs/node/commit/bf412ed77b)] - **deps**: V8: stub backport d5b444bc5a84 (Anna Henningsen) [#32885](https://github.com/nodejs/node/pull/32885) +* [[`fdaa365b0b`](https://github.com/nodejs/node/commit/fdaa365b0b)] - **deps**: V8: stub backport 65238018ca4b and 8d08318e1a85 (Anna Henningsen) [#32885](https://github.com/nodejs/node/pull/32885) +* [[`8198e7882c`](https://github.com/nodejs/node/commit/8198e7882c)] - **deps**: V8: stub backport 9e52d5c5d717 (Anna Henningsen) [#32885](https://github.com/nodejs/node/pull/32885) +* [[`a27852ae7c`](https://github.com/nodejs/node/commit/a27852ae7c)] - **deps**: V8: cherry-pick 98b1ef80c722 (Anna Henningsen) [#32885](https://github.com/nodejs/node/pull/32885) +* [[`e8c7b7a2df`](https://github.com/nodejs/node/commit/e8c7b7a2df)] - **deps**: V8: cherry-pick b5c917ee80cb (Anna Henningsen) [#32885](https://github.com/nodejs/node/pull/32885) +* [[`552cee0cc0`](https://github.com/nodejs/node/commit/552cee0cc0)] - **deps**: V8: cherry-pick 700b1b97e9ab (Anna Henningsen) [#32885](https://github.com/nodejs/node/pull/32885) +* [[`9b7a1b048a`](https://github.com/nodejs/node/commit/9b7a1b048a)] - **deps**: V8: cherry-pick e8ba5699c648 (Anna Henningsen) [#32885](https://github.com/nodejs/node/pull/32885) +* [[`1f02617b05`](https://github.com/nodejs/node/commit/1f02617b05)] - **deps**: V8: cherry-pick 55a01ec7519a (Anna Henningsen) [#32885](https://github.com/nodejs/node/pull/32885) +* [[`da728c482c`](https://github.com/nodejs/node/commit/da728c482c)] - **deps**: V8: cherry-pick 9f0f2cb7f08d (Anna Henningsen) [#32885](https://github.com/nodejs/node/pull/32885) +* [[`2ee8b4a512`](https://github.com/nodejs/node/commit/2ee8b4a512)] - **deps**: V8: cherry-pick e395d1698453 (Anna Henningsen) [#32885](https://github.com/nodejs/node/pull/32885) +* [[`dfc66a6af4`](https://github.com/nodejs/node/commit/dfc66a6af4)] - **deps**: V8: cherry-pick d1253ae95b09 (Anna Henningsen) [#32885](https://github.com/nodejs/node/pull/32885) +* [[`c3ecbc758b`](https://github.com/nodejs/node/commit/c3ecbc758b)] - **deps**: V8: cherry-pick fa3e37e511ee (Anna Henningsen) [#32885](https://github.com/nodejs/node/pull/32885) +* [[`9568fbc7cd`](https://github.com/nodejs/node/commit/9568fbc7cd)] - **deps**: V8: cherry-pick f0057afc2fb6 (Anna Henningsen) [#32885](https://github.com/nodejs/node/pull/32885) +* [[`07d4372d5a`](https://github.com/nodejs/node/commit/07d4372d5a)] - **deps**: V8: cherry-pick 94723c197199 (Anna Henningsen) [#32885](https://github.com/nodejs/node/pull/32885) +* [[`4a11a54f9a`](https://github.com/nodejs/node/commit/4a11a54f9a)] - **deps**: V8: backport 844fe8f7d965 (Anna Henningsen) [#32885](https://github.com/nodejs/node/pull/32885) +* [[`1b7878558a`](https://github.com/nodejs/node/commit/1b7878558a)] - **deps**: V8: cherry-pick 2db93c023379 (Anna Henningsen) [#32885](https://github.com/nodejs/node/pull/32885) +* [[`122937fc67`](https://github.com/nodejs/node/commit/122937fc67)] - **deps**: V8: cherry-pick 4b1447e4bb0e (Anna Henningsen) [#32885](https://github.com/nodejs/node/pull/32885) +* [[`01573ba4ae`](https://github.com/nodejs/node/commit/01573ba4ae)] - **deps**: remove duplicated postmortem metadata entry (Matheus Marchini) [#32521](https://github.com/nodejs/node/pull/32521) +* [[`9290febefa`](https://github.com/nodejs/node/commit/9290febefa)] - **deps**: patch V8 to 8.1.307.26 (Matheus Marchini) [#32521](https://github.com/nodejs/node/pull/32521) +* [[`a9e4cec70d`](https://github.com/nodejs/node/commit/a9e4cec70d)] - ***Revert*** "**deps**: V8: cherry-pick f9257802c1c0" (Matheus Marchini) [#32521](https://github.com/nodejs/node/pull/32521) +* [[`77542a5d57`](https://github.com/nodejs/node/commit/77542a5d57)] - **deps**: revert whitespace changes on V8 (Matheus Marchini) [#32587](https://github.com/nodejs/node/pull/32587) +* [[`9add24ecd3`](https://github.com/nodejs/node/commit/9add24ecd3)] - **doc**: missing brackets (William Bonawentura) [#32657](https://github.com/nodejs/node/pull/32657) +* [[`1796cc0df5`](https://github.com/nodejs/node/commit/1796cc0df5)] - **doc**: improve consistency in usage of NULL (Michael Dawson) [#32726](https://github.com/nodejs/node/pull/32726) +* [[`2662b0c9e3`](https://github.com/nodejs/node/commit/2662b0c9e3)] - **doc**: improve net docs (Robert Nagy) [#32811](https://github.com/nodejs/node/pull/32811) +* [[`5d940de17b`](https://github.com/nodejs/node/commit/5d940de17b)] - **doc**: note that signatures of binary may be from subkeys (Reşat SABIQ) [#32591](https://github.com/nodejs/node/pull/32591) +* [[`3c8dd6d0c3`](https://github.com/nodejs/node/commit/3c8dd6d0c3)] - **doc**: add transform stream destroy() return value (Colin Ihrig) [#32788](https://github.com/nodejs/node/pull/32788) +* [[`39368b34eb`](https://github.com/nodejs/node/commit/39368b34eb)] - **doc**: updated guidance for n-api changes (Michael Dawson) [#32721](https://github.com/nodejs/node/pull/32721) +* [[`cba6e5dc09`](https://github.com/nodejs/node/commit/cba6e5dc09)] - **doc**: remove warning from `response.writeHead` (Cecchi MacNaughton) [#32700](https://github.com/nodejs/node/pull/32700) +* [[`8f7fd8d6aa`](https://github.com/nodejs/node/commit/8f7fd8d6aa)] - **doc**: improve AsyncLocalStorage sample (Andrey Pechkurov) [#32757](https://github.com/nodejs/node/pull/32757) +* [[`a7c75f956f`](https://github.com/nodejs/node/commit/a7c75f956f)] - **doc**: document `buffer.from` returns internal pool buffer (Harshitha KP) [#32703](https://github.com/nodejs/node/pull/32703) +* [[`f6a91156c7`](https://github.com/nodejs/node/commit/f6a91156c7)] - **doc**: add puzpuzpuz to collaborators (Andrey Pechkurov) [#32817](https://github.com/nodejs/node/pull/32817) +* [[`1db8da21f2`](https://github.com/nodejs/node/commit/1db8da21f2)] - **doc**: split process.umask() entry into two (Rich Trott) [#32711](https://github.com/nodejs/node/pull/32711) +* [[`6ade42bb3c`](https://github.com/nodejs/node/commit/6ade42bb3c)] - **doc**: stream.end(cb) cb can be invoked with error (Pranshu Srivastava) [#32238](https://github.com/nodejs/node/pull/32238) +* [[`edb3ffb003`](https://github.com/nodejs/node/commit/edb3ffb003)] - **doc**: fix os.version() Windows API (Colin Ihrig) [#32156](https://github.com/nodejs/node/pull/32156) +* [[`a777cfa843`](https://github.com/nodejs/node/commit/a777cfa843)] - **doc**: remove repetition (Luigi Pinca) [#31868](https://github.com/nodejs/node/pull/31868) +* [[`7c524fb092`](https://github.com/nodejs/node/commit/7c524fb092)] - **doc**: fix Writable.write callback description (Robert Nagy) [#31812](https://github.com/nodejs/node/pull/31812) +* [[`43fb664701`](https://github.com/nodejs/node/commit/43fb664701)] - **doc**: fix missing changelog corrections (Myles Borins) [#31854](https://github.com/nodejs/node/pull/31854) +* [[`a2d6f98e1a`](https://github.com/nodejs/node/commit/a2d6f98e1a)] - **doc**: fix typo (Colin Ihrig) [#31675](https://github.com/nodejs/node/pull/31675) +* [[`17e3f3be76`](https://github.com/nodejs/node/commit/17e3f3be76)] - **doc**: update pr-url for DEP0022 EOL (Colin Ihrig) [#31675](https://github.com/nodejs/node/pull/31675) +* [[`cd0f5a239e`](https://github.com/nodejs/node/commit/cd0f5a239e)] - **doc**: update pr-url for DEP0016 EOL (Colin Ihrig) [#31675](https://github.com/nodejs/node/pull/31675) +* [[`5170daaca5`](https://github.com/nodejs/node/commit/5170daaca5)] - **doc**: fix changelog for v10.18.1 (Andrew Hughes) [#31358](https://github.com/nodejs/node/pull/31358) +* [[`d845915d46`](https://github.com/nodejs/node/commit/d845915d46)] - **doc**: mark Node.js 8 End-of-Life in CHANGELOG (Beth Griggs) [#31152](https://github.com/nodejs/node/pull/31152) +* [[`009a9c475b`](https://github.com/nodejs/node/commit/009a9c475b)] - **doc,src,test**: assign missing deprecation code (Colin Ihrig) [#31674](https://github.com/nodejs/node/pull/31674) +* [[`ed4fbefb71`](https://github.com/nodejs/node/commit/ed4fbefb71)] - **fs**: use finished over destroy w/ cb (Robert Nagy) [#32809](https://github.com/nodejs/node/pull/32809) +* [[`3e9302b2b3`](https://github.com/nodejs/node/commit/3e9302b2b3)] - **fs**: validate the input data before opening file (Yongsheng Zhang) [#31731](https://github.com/nodejs/node/pull/31731) +* [[`1a3e358a1d`](https://github.com/nodejs/node/commit/1a3e358a1d)] - **http**: refactor agent 'free' handler (Robert Nagy) [#32801](https://github.com/nodejs/node/pull/32801) +* [[`399749e4d8`](https://github.com/nodejs/node/commit/399749e4d8)] - **lib**: created isValidCallback helper (Yash Ladha) [#32665](https://github.com/nodejs/node/pull/32665) +* [[`bc55b57e64`](https://github.com/nodejs/node/commit/bc55b57e64)] - **lib**: fix few comment typos in fs/watchers.js (Denys Otrishko) [#31705](https://github.com/nodejs/node/pull/31705) +* [[`f98668ade3`](https://github.com/nodejs/node/commit/f98668ade3)] - **module**: remove experimental modules warning (Guy Bedford) [#31974](https://github.com/nodejs/node/pull/31974) +* [[`fe1bda9aeb`](https://github.com/nodejs/node/commit/fe1bda9aeb)] - **module**: fix memory leak when require error occurs (Qinhui Chen) [#32837](https://github.com/nodejs/node/pull/32837) +* [[`076ba3150d`](https://github.com/nodejs/node/commit/076ba3150d)] - ***Revert*** "**n-api**: detect deadlocks in thread-safe function" (Gabriel Schulhof) [#32880](https://github.com/nodejs/node/pull/32880) +* [[`1092bb94f4`](https://github.com/nodejs/node/commit/1092bb94f4)] - **process**: suggest --trace-warnings when printing warning (Anna Henningsen) [#32797](https://github.com/nodejs/node/pull/32797) +* [[`d19a2c33b3`](https://github.com/nodejs/node/commit/d19a2c33b3)] - **src**: migrate measureMemory to new v8 api (gengjiawen) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`a63db7fb5e`](https://github.com/nodejs/node/commit/a63db7fb5e)] - **src**: remove deprecated wasm type check (Clemens Backes) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`c080b2d821`](https://github.com/nodejs/node/commit/c080b2d821)] - **src**: avoid calling deprecated method (Clemens Backes) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`7ed0d1439e`](https://github.com/nodejs/node/commit/7ed0d1439e)] - **src**: remove use of deprecated Symbol::Name() (Colin Ihrig) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`59eeb3b5b9`](https://github.com/nodejs/node/commit/59eeb3b5b9)] - **src**: stop overriding deprecated V8 methods (Clemens Backes) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`339c192ddb`](https://github.com/nodejs/node/commit/339c192ddb)] - **src**: update NODE\_MODULE\_VERSION to 83 (Matheus Marchini) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`6681a685a9`](https://github.com/nodejs/node/commit/6681a685a9)] - **src**: remove unused using in node\_worker.cc (Daniel Bevenius) [#32840](https://github.com/nodejs/node/pull/32840) +* [[`b9d9f91a80`](https://github.com/nodejs/node/commit/b9d9f91a80)] - **src**: use basename(argv0) for --trace-uncaught suggestion (Anna Henningsen) [#32798](https://github.com/nodejs/node/pull/32798) +* [[`24e1e28b38`](https://github.com/nodejs/node/commit/24e1e28b38)] - **src**: ignore GCC -Wcast-function-type for v8.h (Daniel Bevenius) [#32679](https://github.com/nodejs/node/pull/32679) +* [[`a946189ccd`](https://github.com/nodejs/node/commit/a946189ccd)] - **src**: add AliasedStruct utility (James M Snell) [#32778](https://github.com/nodejs/node/pull/32778) +* [[`457f1f1ed0`](https://github.com/nodejs/node/commit/457f1f1ed0)] - **src**: remove unused v8 Array namespace (Juan José Arboleda) [#32749](https://github.com/nodejs/node/pull/32749) +* [[`b68e26ee70`](https://github.com/nodejs/node/commit/b68e26ee70)] - **src**: flush V8 interrupts from Environment dtor (Anna Henningsen) [#32523](https://github.com/nodejs/node/pull/32523) +* [[`96bf137cca`](https://github.com/nodejs/node/commit/96bf137cca)] - **src**: use env-\>RequestInterrupt() for inspector MainThreadInterface (Anna Henningsen) [#32523](https://github.com/nodejs/node/pull/32523) +* [[`72da426780`](https://github.com/nodejs/node/commit/72da426780)] - **src**: use env-\>RequestInterrupt() for inspector io thread start (Anna Henningsen) [#32523](https://github.com/nodejs/node/pull/32523) +* [[`99c9b2368c`](https://github.com/nodejs/node/commit/99c9b2368c)] - **src**: fix cleanup hook removal for InspectorTimer (Anna Henningsen) [#32523](https://github.com/nodejs/node/pull/32523) +* [[`6dffd6b3de`](https://github.com/nodejs/node/commit/6dffd6b3de)] - **src**: make `Environment::interrupt\_data\_` atomic (Anna Henningsen) [#32523](https://github.com/nodejs/node/pull/32523) +* [[`8c5ad1392f`](https://github.com/nodejs/node/commit/8c5ad1392f)] - **src**: initialize inspector before RunBootstrapping() (Anna Henningsen) [#32672](https://github.com/nodejs/node/pull/32672) +* [[`eafd64b1c8`](https://github.com/nodejs/node/commit/eafd64b1c8)] - **src**: consistently declare BindingData class (Sam Roberts) [#32677](https://github.com/nodejs/node/pull/32677) +* [[`78c82a38ac`](https://github.com/nodejs/node/commit/78c82a38ac)] - **src**: move fs state out of Environment (Anna Henningsen) [#32538](https://github.com/nodejs/node/pull/32538) +* [[`7005670f34`](https://github.com/nodejs/node/commit/7005670f34)] - **src**: move http parser state out of Environment (Anna Henningsen) [#32538](https://github.com/nodejs/node/pull/32538) +* [[`19b671506c`](https://github.com/nodejs/node/commit/19b671506c)] - **src**: move v8 stats buffers out of Environment (Anna Henningsen) [#32538](https://github.com/nodejs/node/pull/32538) +* [[`4df24f040d`](https://github.com/nodejs/node/commit/4df24f040d)] - **src**: move HTTP/2 state out of Environment (Anna Henningsen) [#32538](https://github.com/nodejs/node/pull/32538) +* [[`1fc3de908e`](https://github.com/nodejs/node/commit/1fc3de908e)] - **src**: make creating per-binding data structures easier (Anna Henningsen) [#32538](https://github.com/nodejs/node/pull/32538) +* [[`0e9f9b7592`](https://github.com/nodejs/node/commit/0e9f9b7592)] - **src**: include AsyncWrap provider strings in snapshot (Anna Henningsen) [#32572](https://github.com/nodejs/node/pull/32572) +* [[`effebf87ab`](https://github.com/nodejs/node/commit/effebf87ab)] - **src**: remove unused v8 namespace (Juan José Arboleda) [#32375](https://github.com/nodejs/node/pull/32375) +* [[`d23eed256b`](https://github.com/nodejs/node/commit/d23eed256b)] - **src**: remove calls to deprecated ArrayBuffer methods (Michaël Zasso) [#32358](https://github.com/nodejs/node/pull/32358) +* [[`f3682102dc`](https://github.com/nodejs/node/commit/f3682102dc)] - **src**: give Http2Session JS fields their own backing store (Anna Henningsen) [#31648](https://github.com/nodejs/node/pull/31648) +* [[`90f7a5c010`](https://github.com/nodejs/node/commit/90f7a5c010)] - **src**: set arraybuffer\_untransferable\_private\_symbol (Thang Tran) [#31053](https://github.com/nodejs/node/pull/31053) +* [[`d06efafe6b`](https://github.com/nodejs/node/commit/d06efafe6b)] - **src**: explicitly allocate backing stores for v8 stat buffers (Anna Henningsen) [#30946](https://github.com/nodejs/node/pull/30946) +* [[`917fedd21a`](https://github.com/nodejs/node/commit/917fedd21a)] - **src**: unset NODE\_VERSION\_IS\_RELEASE from master (Michaël Zasso) [#30584](https://github.com/nodejs/node/pull/30584) +* [[`69f19f4ccd`](https://github.com/nodejs/node/commit/69f19f4ccd)] - **src**: remove uses of deprecated wasm TransferrableModule (Clemens Backes) [#30026](https://github.com/nodejs/node/pull/30026) +* [[`acac5df260`](https://github.com/nodejs/node/commit/acac5df260)] - **src,doc**: add documentation for per-binding state pattern (Anna Henningsen) [#32538](https://github.com/nodejs/node/pull/32538) +* [[`ad4c10e824`](https://github.com/nodejs/node/commit/ad4c10e824)] - **stream**: improve comments regarding end() errors (Robert Nagy) [#32839](https://github.com/nodejs/node/pull/32839) +* [[`6e5c23b6c8`](https://github.com/nodejs/node/commit/6e5c23b6c8)] - **stream**: update comment to indicate unused API (Robert Nagy) [#32808](https://github.com/nodejs/node/pull/32808) +* [[`21bd6679ce`](https://github.com/nodejs/node/commit/21bd6679ce)] - **stream**: fix finished typo (Robert Nagy) [#31881](https://github.com/nodejs/node/pull/31881) +* [[`85c6fcd1cd`](https://github.com/nodejs/node/commit/85c6fcd1cd)] - **stream**: avoid writing to writable (Robert Nagy) [#31805](https://github.com/nodejs/node/pull/31805) +* [[`0875837417`](https://github.com/nodejs/node/commit/0875837417)] - **stream**: fix async iterator destroyed error order (Robert Nagy) [#31700](https://github.com/nodejs/node/pull/31700) +* [[`b9a7625fdf`](https://github.com/nodejs/node/commit/b9a7625fdf)] - **stream**: removed outdated TODO (Robert Nagy) [#31701](https://github.com/nodejs/node/pull/31701) +* [[`68e1288e00`](https://github.com/nodejs/node/commit/68e1288e00)] - **test**: mark addons/zlib-bindings/test flaky on arm (Michaël Zasso) [#32885](https://github.com/nodejs/node/pull/32885) +* [[`a09bf3ad5f`](https://github.com/nodejs/node/commit/a09bf3ad5f)] - **test**: replace console.log/error() with debuglog (daemon1024) [#32692](https://github.com/nodejs/node/pull/32692) +* [[`d1b41bbd86`](https://github.com/nodejs/node/commit/d1b41bbd86)] - **test**: only detect uname on supported os (Xu Meng) [#32833](https://github.com/nodejs/node/pull/32833) +* [[`4bb29ed044`](https://github.com/nodejs/node/commit/4bb29ed044)] - **test**: mark cpu-prof-dir-worker flaky on all (Sam Roberts) [#32828](https://github.com/nodejs/node/pull/32828) +* [[`e18a40e42d`](https://github.com/nodejs/node/commit/e18a40e42d)] - **test**: replace equal with strictEqual (Jesus Hernandez) [#32727](https://github.com/nodejs/node/pull/32727) +* [[`320f297a35`](https://github.com/nodejs/node/commit/320f297a35)] - **test**: mark test-worker-prof flaky on arm (Sam Roberts) [#32826](https://github.com/nodejs/node/pull/32826) +* [[`4b5658b536`](https://github.com/nodejs/node/commit/4b5658b536)] - **test**: mark test-http2-reset-flood flaky on all (Sam Roberts) [#32825](https://github.com/nodejs/node/pull/32825) +* [[`ead51be541`](https://github.com/nodejs/node/commit/ead51be541)] - **test**: cover node entry type in perf\_hooks (Julian Duque) [#32751](https://github.com/nodejs/node/pull/32751) +* [[`9e5189a560`](https://github.com/nodejs/node/commit/9e5189a560)] - **test**: use symlinks to copy shells (John Kleinschmidt) [#32129](https://github.com/nodejs/node/pull/32129) +* [[`c5763e8dc1`](https://github.com/nodejs/node/commit/c5763e8dc1)] - **test**: wait for message from parent in embedding cctest (Anna Henningsen) [#32563](https://github.com/nodejs/node/pull/32563) +* [[`c3204a8787`](https://github.com/nodejs/node/commit/c3204a8787)] - **test**: use common.buildType in embedding test (Anna Henningsen) [#32422](https://github.com/nodejs/node/pull/32422) +* [[`f2cc28aec3`](https://github.com/nodejs/node/commit/f2cc28aec3)] - **test**: use InitializeNodeWithArgs in cctest (Anna Henningsen) [#32406](https://github.com/nodejs/node/pull/32406) +* [[`df1592d2e9`](https://github.com/nodejs/node/commit/df1592d2e9)] - **test**: async iterate destroyed stream (Robert Nagy) [#28995](https://github.com/nodejs/node/pull/28995) +* [[`5100e84f4b`](https://github.com/nodejs/node/commit/5100e84f4b)] - **test**: fix flaky test-fs-promises-file-handle-close (Anna Henningsen) [#31687](https://github.com/nodejs/node/pull/31687) +* [[`52944b834a`](https://github.com/nodejs/node/commit/52944b834a)] - **test**: remove test (Clemens Backes) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`119fdf6813`](https://github.com/nodejs/node/commit/119fdf6813)] - **test**: remove checks for deserializing wasm (Matheus Marchini) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`add5f6e5cd`](https://github.com/nodejs/node/commit/add5f6e5cd)] - **tls**: provide default cipher list from command line (Anna Henningsen) [#32760](https://github.com/nodejs/node/pull/32760) +* [[`405ae1909b`](https://github.com/nodejs/node/commit/405ae1909b)] - **tools**: update V8 gypfiles for 8.1 (Matheus Marchini) [#32116](https://github.com/nodejs/node/pull/32116) +* [[`7fe61222ef`](https://github.com/nodejs/node/commit/7fe61222ef)] - **worker**: mention argument name in type check message (Anna Henningsen) [#32815](https://github.com/nodejs/node/pull/32815) +* [[`7147df53e8`](https://github.com/nodejs/node/commit/7147df53e8)] - **worker**: fix type check in receiveMessageOnPort (Anna Henningsen) [#32745](https://github.com/nodejs/node/pull/32745) +* [[`0c545f0f72`](https://github.com/nodejs/node/commit/0c545f0f72)] - **zlib**: emits 'close' event after readable 'end' (Sergey Zelenov) [#32050](https://github.com/nodejs/node/pull/32050) diff --git a/doc/changelogs/CHANGELOG_V4.md b/doc/changelogs/CHANGELOG_V4.md index b60ddea3b53b89..2f5c81319025c7 100644 --- a/doc/changelogs/CHANGELOG_V4.md +++ b/doc/changelogs/CHANGELOG_V4.md @@ -57,6 +57,7 @@ * Other Versions + * [14.x](CHANGELOG_V14.md) * [13.x](CHANGELOG_V13.md) * [12.x](CHANGELOG_V12.md) * [11.x](CHANGELOG_V11.md) diff --git a/doc/changelogs/CHANGELOG_V5.md b/doc/changelogs/CHANGELOG_V5.md index 1ce9a73eb6d7ef..ac338886c858c6 100644 --- a/doc/changelogs/CHANGELOG_V5.md +++ b/doc/changelogs/CHANGELOG_V5.md @@ -33,6 +33,7 @@ * Other Versions + * [14.x](CHANGELOG_V14.md) * [13.x](CHANGELOG_V13.md) * [12.x](CHANGELOG_V12.md) * [11.x](CHANGELOG_V11.md) diff --git a/doc/changelogs/CHANGELOG_V6.md b/doc/changelogs/CHANGELOG_V6.md index 72f254a9dd19c9..763ff802884781 100644 --- a/doc/changelogs/CHANGELOG_V6.md +++ b/doc/changelogs/CHANGELOG_V6.md @@ -62,6 +62,7 @@ * Other Versions + * [14.x](CHANGELOG_V14.md) * [13.x](CHANGELOG_V13.md) * [12.x](CHANGELOG_V12.md) * [11.x](CHANGELOG_V11.md) diff --git a/doc/changelogs/CHANGELOG_V7.md b/doc/changelogs/CHANGELOG_V7.md index 4081c291175a9e..5a06890f58685b 100644 --- a/doc/changelogs/CHANGELOG_V7.md +++ b/doc/changelogs/CHANGELOG_V7.md @@ -31,6 +31,7 @@ * Other Versions + * [14.x](CHANGELOG_V14.md) * [13.x](CHANGELOG_V13.md) * [12.x](CHANGELOG_V12.md) * [11.x](CHANGELOG_V11.md) diff --git a/doc/changelogs/CHANGELOG_V8.md b/doc/changelogs/CHANGELOG_V8.md index fbd1721e7c60b6..33fa32948389b6 100644 --- a/doc/changelogs/CHANGELOG_V8.md +++ b/doc/changelogs/CHANGELOG_V8.md @@ -53,6 +53,7 @@ * Other Versions + * [14.x](CHANGELOG_V14.md) * [13.x](CHANGELOG_V13.md) * [12.x](CHANGELOG_V12.md) * [11.x](CHANGELOG_V11.md) diff --git a/doc/changelogs/CHANGELOG_V9.md b/doc/changelogs/CHANGELOG_V9.md index 6687365eb89eb4..f58341bb34b52d 100644 --- a/doc/changelogs/CHANGELOG_V9.md +++ b/doc/changelogs/CHANGELOG_V9.md @@ -32,6 +32,7 @@ * Other Versions + * [14.x](CHANGELOG_V14.md) * [13.x](CHANGELOG_V13.md) * [12.x](CHANGELOG_V12.md) * [11.x](CHANGELOG_V11.md) diff --git a/src/node_version.h b/src/node_version.h index 47f86e854be5b6..3107cbfc17533e 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -22,7 +22,7 @@ #ifndef SRC_NODE_VERSION_H_ #define SRC_NODE_VERSION_H_ -#define NODE_MAJOR_VERSION 14 +#define NODE_MAJOR_VERSION 15 #define NODE_MINOR_VERSION 0 #define NODE_PATCH_VERSION 0 From 438514d36aa899ee62e760c401564b1ce9314391 Mon Sep 17 00:00:00 2001 From: Edward Elric Date: Sun, 19 Apr 2020 16:40:18 +0800 Subject: [PATCH 4/6] doc: fix typo in security-release-process.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/32926 Reviewed-By: David Carlier Reviewed-By: James M Snell Reviewed-By: Zeyu Yang Reviewed-By: Colin Ihrig Reviewed-By: Juan José Arboleda --- doc/guides/security-release-process.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/guides/security-release-process.md b/doc/guides/security-release-process.md index 55951f94d4ae1f..73d27ae7c60d8c 100644 --- a/doc/guides/security-release-process.md +++ b/doc/guides/security-release-process.md @@ -2,7 +2,7 @@ The security release process covers the steps required to plan/implement a security release. This document is copied into the description of the Next -Security Release, and used to track progess on the release. It contains ***TEXT +Security Release, and used to track progress on the release. It contains ***TEXT LIKE THIS*** which will be replaced during the release process with the information described. From 46ec9ab7d81f7dac59b2bf9afb67896564b4f586 Mon Sep 17 00:00:00 2001 From: Myles Borins Date: Sat, 18 Apr 2020 11:27:54 -0400 Subject: [PATCH 5/6] module: partial doc removal of --experimental-modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes `--experimental-modules` from showing up in `node -h` and also removes the documentation from the man pages. It will still work as a no-op, and is still included in cli.md Refs: https://github.com/nodejs/modules/issues/502 PR-URL: https://github.com/nodejs/node/pull/32915 Reviewed-By: Guy Bedford Reviewed-By: Geoffrey Booth Reviewed-By: David Carlier Reviewed-By: Michaël Zasso Reviewed-By: Franziska Hinkelmann Reviewed-By: James M Snell --- doc/node.1 | 3 --- src/node_options.cc | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/doc/node.1 b/doc/node.1 index 9bb344fdf27b2d..ec2642170aee6f 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -132,9 +132,6 @@ Specify the .Ar module to use as a custom module loader. . -.It Fl -experimental-modules -Enable experimental latest experimental modules features. -. .It Fl -experimental-policy Use the specified file as a security policy. . diff --git a/src/node_options.cc b/src/node_options.cc index 4148cfc04eb2ac..3b9142c19e98a8 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -285,7 +285,7 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { kAllowedInEnvironment); AddAlias("--loader", "--experimental-loader"); AddOption("--experimental-modules", - "experimental modules features", + "", &EnvironmentOptions::experimental_modules, kAllowedInEnvironment); AddOption("--experimental-wasm-modules", From 91ca22106c8d20dd4b09741c59c2f24f3a287277 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Wed, 15 Apr 2020 15:21:32 -0700 Subject: [PATCH 6/6] http2: refactor and cleanup http2 * cleanup constants in http2 binding The error constants were just doing some weird things. Cleanup and improve maintainability. * simplify settings to reduce duplicate code * improve style consistency and correctness Use snake_case for getters and setters at c++ level, avoid unnecessary use of enums, use consistent style for exported vs. internal constants, avoid unnecessary memory info reporting, use setters/getters for flags_ for improved code readability * make EmitStatistics function private * un-nest Http2Settings and Http2Ping * refactoring and cleanup of Http2Settings and Http2Ping * avoid ** syntax for readability The **session and **stream syntax for getting the underlying nghttp2 pointers is not ideal for readability * use const references for Http2Priority * remove unnecessary GetStream function * refactor Http2Scope to use BaseObjectPtr * move utility function to anonymous namespace * refactor and simplify Origins * Use an AllocatedBuffer instead of MaybeStackBuffer * Use a const reference instead of pointer * use BaseObjectPtr for Http2Streams map * move MemoryInfo impl to cc Signed-off-by: James M Snell PR-URL: https://github.com/nodejs/node/pull/32884 Reviewed-By: Matteo Collina Reviewed-By: Franziska Hinkelmann --- src/node_http2.cc | 994 +++++++++--------- src/node_http2.h | 500 +++++---- test/parallel/test-http2-getpackedsettings.js | 11 +- 3 files changed, 799 insertions(+), 706 deletions(-) diff --git a/src/node_http2.cc b/src/node_http2.cc index 7477bfbb6d8c10..385a2352040c4e 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -21,6 +21,7 @@ using v8::ArrayBuffer; using v8::ArrayBufferView; using v8::Boolean; using v8::Context; +using v8::EscapableHandleScope; using v8::Float64Array; using v8::Function; using v8::FunctionCallbackInfo; @@ -30,7 +31,6 @@ using v8::Integer; using v8::Isolate; using v8::Local; using v8::MaybeLocal; -using v8::NewStringType; using v8::Number; using v8::Object; using v8::ObjectTemplate; @@ -48,15 +48,9 @@ namespace { const char zero_bytes_256[256] = {}; -inline Http2Stream* GetStream(Http2Session* session, - int32_t id, - nghttp2_data_source* source) { - Http2Stream* stream = static_cast(source->ptr); - if (stream == nullptr) - stream = session->FindStream(id); - CHECK_NOT_NULL(stream); - CHECK_EQ(id, stream->id()); - return stream; +bool HasHttp2Observer(Environment* env) { + AliasedUint32Array& observers = env->performance_state()->observers; + return observers[performance::NODE_PERFORMANCE_ENTRY_TYPE_HTTP2] != 0; } } // anonymous namespace @@ -75,36 +69,27 @@ const Http2Session::Callbacks Http2Session::callback_struct_saved[2] = { // For example: // // Http2Scope h2scope(session); -// nghttp2_submit_ping(**session, ... ); +// nghttp2_submit_ping(session->session(), ... ); // // When the Http2Scope passes out of scope and is deconstructed, it will // call Http2Session::MaybeScheduleWrite(). Http2Scope::Http2Scope(Http2Stream* stream) : Http2Scope(stream->session()) {} -Http2Scope::Http2Scope(Http2Session* session) { - if (session == nullptr) - return; +Http2Scope::Http2Scope(Http2Session* session) : session_(session) { + if (!session_) return; - if (session->flags_ & (SESSION_STATE_HAS_SCOPE | - SESSION_STATE_WRITE_SCHEDULED)) { - // There is another scope further below on the stack, or it is already - // known that a write is scheduled. In either case, there is nothing to do. + // If there is another scope further below on the stack, or + // a write is already scheduled, there's nothing to do. + if (session_->is_in_scope() || session_->is_write_scheduled()) { + session_.reset(); return; } - session->flags_ |= SESSION_STATE_HAS_SCOPE; - session_ = session; - - // Always keep the session object alive for at least as long as - // this scope is active. - session_handle_ = session->object(); - CHECK(!session_handle_.IsEmpty()); + session_->set_in_scope(); } Http2Scope::~Http2Scope() { - if (session_ == nullptr) - return; - - session_->flags_ &= ~SESSION_STATE_HAS_SCOPE; + if (!session_) return; + session_->set_in_scope(false); session_->MaybeScheduleWrite(); } @@ -112,7 +97,7 @@ Http2Scope::~Http2Scope() { // instances to configure an appropriate nghttp2_options struct. The class // uses a single TypedArray instance that is shared with the JavaScript side // to more efficiently pass values back and forth. -Http2Options::Http2Options(Http2State* http2_state, nghttp2_session_type type) { +Http2Options::Http2Options(Http2State* http2_state, SessionType type) { nghttp2_option* option; CHECK_EQ(nghttp2_option_new(&option), 0); CHECK_NOT_NULL(option); @@ -171,10 +156,10 @@ Http2Options::Http2Options(Http2State* http2_state, nghttp2_session_type type) { // this is set on a per-session basis, but eventually we may switch to // a per-stream setting, giving users greater control if (flags & (1 << IDX_OPTIONS_PADDING_STRATEGY)) { - padding_strategy_type strategy = - static_cast( + PaddingStrategy strategy = + static_cast( buffer.GetValue(IDX_OPTIONS_PADDING_STRATEGY)); - SetPaddingStrategy(strategy); + set_padding_strategy(strategy); } // The max header list pairs option controls the maximum number of @@ -182,7 +167,7 @@ Http2Options::Http2Options(Http2State* http2_state, nghttp2_session_type type) { // if the remote peer sends more than this amount, the stream will be // automatically closed with an RST_STREAM. if (flags & (1 << IDX_OPTIONS_MAX_HEADER_LIST_PAIRS)) - SetMaxHeaderPairs(buffer[IDX_OPTIONS_MAX_HEADER_LIST_PAIRS]); + set_max_header_pairs(buffer[IDX_OPTIONS_MAX_HEADER_LIST_PAIRS]); // The HTTP2 specification places no limits on the number of HTTP2 // PING frames that can be sent. In order to prevent PINGS from being @@ -190,7 +175,7 @@ Http2Options::Http2Options(Http2State* http2_state, nghttp2_session_type type) { // on the number of unacknowledged PINGS that can be sent at any given // time. if (flags & (1 << IDX_OPTIONS_MAX_OUTSTANDING_PINGS)) - SetMaxOutstandingPings(buffer[IDX_OPTIONS_MAX_OUTSTANDING_PINGS]); + set_max_outstanding_pings(buffer[IDX_OPTIONS_MAX_OUTSTANDING_PINGS]); // The HTTP2 specification places no limits on the number of HTTP2 // SETTINGS frames that can be sent. In order to prevent PINGS from being @@ -198,7 +183,7 @@ Http2Options::Http2Options(Http2State* http2_state, nghttp2_session_type type) { // on the number of unacknowledged SETTINGS that can be sent at any given // time. if (flags & (1 << IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS)) - SetMaxOutstandingSettings(buffer[IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS]); + set_max_outstanding_settings(buffer[IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS]); // The HTTP2 specification places no limits on the amount of memory // that a session can consume. In order to prevent abuse, we place a @@ -209,131 +194,133 @@ Http2Options::Http2Options(Http2State* http2_state, nghttp2_session_type type) { // Important: The maxSessionMemory option in javascript is expressed in // terms of MB increments (i.e. the value 1 == 1 MB) if (flags & (1 << IDX_OPTIONS_MAX_SESSION_MEMORY)) - SetMaxSessionMemory(buffer[IDX_OPTIONS_MAX_SESSION_MEMORY] * 1000000); + set_max_session_memory(buffer[IDX_OPTIONS_MAX_SESSION_MEMORY] * 1000000); } -void Http2Session::Http2Settings::Init(Http2State* http2_state) { +#define GRABSETTING(entries, count, name) \ + do { \ + if (flags & (1 << IDX_SETTINGS_ ## name)) { \ + uint32_t val = buffer[IDX_SETTINGS_ ## name]; \ + entries[count++] = \ + nghttp2_settings_entry {NGHTTP2_SETTINGS_ ## name, val}; \ + } } while (0) + +size_t Http2Settings::Init( + Http2State* http2_state, + nghttp2_settings_entry* entries) { AliasedUint32Array& buffer = http2_state->settings_buffer; uint32_t flags = buffer[IDX_SETTINGS_COUNT]; - size_t n = 0; - -#define GRABSETTING(N, trace) \ - if (flags & (1 << IDX_SETTINGS_##N)) { \ - uint32_t val = buffer[IDX_SETTINGS_##N]; \ - if (session_ != nullptr) \ - Debug(session_, "setting " trace ": %d\n", val); \ - entries_[n++] = \ - nghttp2_settings_entry {NGHTTP2_SETTINGS_##N, val}; \ - } + size_t count = 0; - GRABSETTING(HEADER_TABLE_SIZE, "header table size"); - GRABSETTING(MAX_CONCURRENT_STREAMS, "max concurrent streams"); - GRABSETTING(MAX_FRAME_SIZE, "max frame size"); - GRABSETTING(INITIAL_WINDOW_SIZE, "initial window size"); - GRABSETTING(MAX_HEADER_LIST_SIZE, "max header list size"); - GRABSETTING(ENABLE_PUSH, "enable push"); - GRABSETTING(ENABLE_CONNECT_PROTOCOL, "enable connect protocol"); - -#undef GRABSETTING +#define V(name) GRABSETTING(entries, count, name); + HTTP2_SETTINGS(V) +#undef V - count_ = n; + return count; } +#undef GRABSETTING // The Http2Settings class is used to configure a SETTINGS frame that is // to be sent to the connected peer. The settings are set using a TypedArray // that is shared with the JavaScript side. -Http2Session::Http2Settings::Http2Settings(Http2State* http2_state, - Http2Session* session, - Local obj, - uint64_t start_time) - : AsyncWrap(http2_state->env(), obj, PROVIDER_HTTP2SETTINGS), +Http2Settings::Http2Settings(Http2Session* session, + Local obj, + Local callback, + uint64_t start_time) + : AsyncWrap(session->env(), obj, PROVIDER_HTTP2SETTINGS), session_(session), startTime_(start_time) { - Init(http2_state); + callback_.Reset(env()->isolate(), callback); + count_ = Init(session->http2_state(), entries_); +} + +Local Http2Settings::callback() const { + return callback_.Get(env()->isolate()); +} + +void Http2Settings::MemoryInfo(MemoryTracker* tracker) const { + tracker->TrackField("callback", callback_); } // Generates a Buffer that contains the serialized payload of a SETTINGS // frame. This can be used, for instance, to create the Base64-encoded // content of an Http2-Settings header field. -Local Http2Session::Http2Settings::Pack() { - const size_t len = count_ * 6; - Local buf = Buffer::New(env(), len).ToLocalChecked(); +Local Http2Settings::Pack() { + return Pack(session_->env(), count_, entries_); +} + +Local Http2Settings::Pack(Http2State* state) { + nghttp2_settings_entry entries[IDX_SETTINGS_COUNT]; + size_t count = Init(state, entries); + return Pack(state->env(), count, entries); +} + +Local Http2Settings::Pack( + Environment* env, + size_t count, + const nghttp2_settings_entry* entries) { + EscapableHandleScope scope(env->isolate()); + const size_t size = count * 6; + AllocatedBuffer buffer = env->AllocateManaged(size); ssize_t ret = nghttp2_pack_settings_payload( - reinterpret_cast(Buffer::Data(buf)), len, - &entries_[0], count_); - if (ret >= 0) - return buf; - else - return Undefined(env()->isolate()); + reinterpret_cast(buffer.data()), + size, + entries, + count); + Local buf = Undefined(env->isolate()); + if (ret >= 0) buf = buffer.ToBuffer().ToLocalChecked(); + return scope.Escape(buf); } // Updates the shared TypedArray with the current remote or local settings for // the session. -void Http2Session::Http2Settings::Update(Http2Session* session, - get_setting fn) { +void Http2Settings::Update(Http2Session* session, get_setting fn) { AliasedUint32Array& buffer = session->http2_state()->settings_buffer; - buffer[IDX_SETTINGS_HEADER_TABLE_SIZE] = - fn(**session, NGHTTP2_SETTINGS_HEADER_TABLE_SIZE); - buffer[IDX_SETTINGS_MAX_CONCURRENT_STREAMS] = - fn(**session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS); - buffer[IDX_SETTINGS_INITIAL_WINDOW_SIZE] = - fn(**session, NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE); - buffer[IDX_SETTINGS_MAX_FRAME_SIZE] = - fn(**session, NGHTTP2_SETTINGS_MAX_FRAME_SIZE); - buffer[IDX_SETTINGS_MAX_HEADER_LIST_SIZE] = - fn(**session, NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE); - buffer[IDX_SETTINGS_ENABLE_PUSH] = - fn(**session, NGHTTP2_SETTINGS_ENABLE_PUSH); - buffer[IDX_SETTINGS_ENABLE_CONNECT_PROTOCOL] = - fn(**session, NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL); + +#define V(name) \ + buffer[IDX_SETTINGS_ ## name] = \ + fn(session->session(), NGHTTP2_SETTINGS_ ## name); + HTTP2_SETTINGS(V) +#undef V } // Initializes the shared TypedArray with the default settings values. -void Http2Session::Http2Settings::RefreshDefaults(Http2State* http2_state) { +void Http2Settings::RefreshDefaults(Http2State* http2_state) { AliasedUint32Array& buffer = http2_state->settings_buffer; + uint32_t flags = 0; + +#define V(name) \ + do { \ + buffer[IDX_SETTINGS_ ## name] = DEFAULT_SETTINGS_ ## name; \ + flags |= 1 << IDX_SETTINGS_ ## name; \ + } while (0); + HTTP2_SETTINGS(V) +#undef V + + buffer[IDX_SETTINGS_COUNT] = flags; +} - buffer[IDX_SETTINGS_HEADER_TABLE_SIZE] = - DEFAULT_SETTINGS_HEADER_TABLE_SIZE; - buffer[IDX_SETTINGS_ENABLE_PUSH] = - DEFAULT_SETTINGS_ENABLE_PUSH; - buffer[IDX_SETTINGS_MAX_CONCURRENT_STREAMS] = - DEFAULT_SETTINGS_MAX_CONCURRENT_STREAMS; - buffer[IDX_SETTINGS_INITIAL_WINDOW_SIZE] = - DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE; - buffer[IDX_SETTINGS_MAX_FRAME_SIZE] = - DEFAULT_SETTINGS_MAX_FRAME_SIZE; - buffer[IDX_SETTINGS_MAX_HEADER_LIST_SIZE] = - DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE; - buffer[IDX_SETTINGS_ENABLE_CONNECT_PROTOCOL] = - DEFAULT_SETTINGS_ENABLE_CONNECT_PROTOCOL; - buffer[IDX_SETTINGS_COUNT] = - (1 << IDX_SETTINGS_HEADER_TABLE_SIZE) | - (1 << IDX_SETTINGS_ENABLE_PUSH) | - (1 << IDX_SETTINGS_MAX_CONCURRENT_STREAMS) | - (1 << IDX_SETTINGS_INITIAL_WINDOW_SIZE) | - (1 << IDX_SETTINGS_MAX_FRAME_SIZE) | - (1 << IDX_SETTINGS_MAX_HEADER_LIST_SIZE) | - (1 << IDX_SETTINGS_ENABLE_CONNECT_PROTOCOL); -} - - -void Http2Session::Http2Settings::Send() { - Http2Scope h2scope(session_); - CHECK_EQ(nghttp2_submit_settings(**session_, NGHTTP2_FLAG_NONE, - &entries_[0], count_), 0); -} - -void Http2Session::Http2Settings::Done(bool ack) { + +void Http2Settings::Send() { + Http2Scope h2scope(session_.get()); + CHECK_EQ(nghttp2_submit_settings( + session_->session(), + NGHTTP2_FLAG_NONE, + &entries_[0], + count_), 0); +} + +void Http2Settings::Done(bool ack) { uint64_t end = uv_hrtime(); double duration = (end - startTime_) / 1e6; Local argv[] = { - Boolean::New(env()->isolate(), ack), + ack ? v8::True(env()->isolate()) : v8::False(env()->isolate()), Number::New(env()->isolate(), duration) }; - MakeCallback(env()->ondone_string(), arraysize(argv), argv); + MakeCallback(callback(), arraysize(argv), argv); } // The Http2Priority class initializes an appropriate nghttp2_priority_spec @@ -364,34 +351,32 @@ const char* Http2Session::TypeName() const { } } -Origins::Origins(Isolate* isolate, - Local context, - Local origin_string, - size_t origin_count) : count_(origin_count) { +Origins::Origins( + Environment* env, + Local origin_string, + size_t origin_count) + : count_(origin_count) { int origin_string_len = origin_string->Length(); if (count_ == 0) { CHECK_EQ(origin_string_len, 0); return; } - // Allocate a single buffer with count_ nghttp2_nv structs, followed - // by the raw header data as passed from JS. This looks like: - // | possible padding | nghttp2_nv | nghttp2_nv | ... | header contents | - buf_.AllocateSufficientStorage((alignof(nghttp2_origin_entry) - 1) + - count_ * sizeof(nghttp2_origin_entry) + - origin_string_len); + buf_ = env->AllocateManaged((alignof(nghttp2_origin_entry) - 1) + + count_ * sizeof(nghttp2_origin_entry) + + origin_string_len); // Make sure the start address is aligned appropriately for an nghttp2_nv*. char* start = reinterpret_cast( - RoundUp(reinterpret_cast(*buf_), + RoundUp(reinterpret_cast(buf_.data()), alignof(nghttp2_origin_entry))); char* origin_contents = start + (count_ * sizeof(nghttp2_origin_entry)); nghttp2_origin_entry* const nva = reinterpret_cast(start); - CHECK_LE(origin_contents + origin_string_len, *buf_ + buf_.length()); + CHECK_LE(origin_contents + origin_string_len, buf_.data() + buf_.size()); CHECK_EQ(origin_string->WriteOneByte( - isolate, + env->isolate(), reinterpret_cast(origin_contents), 0, origin_string_len, @@ -469,7 +454,7 @@ void Http2Session::DecreaseAllocatedSize(size_t size) { Http2Session::Http2Session(Http2State* http2_state, Local wrap, - nghttp2_session_type type) + SessionType type) : AsyncWrap(http2_state->env(), wrap, AsyncWrap::PROVIDER_HTTP2SESSION), js_fields_(http2_state->env()->isolate()), session_type_(type), @@ -480,18 +465,18 @@ Http2Session::Http2Session(Http2State* http2_state, // Capture the configuration options for this session Http2Options opts(http2_state, type); - max_session_memory_ = opts.GetMaxSessionMemory(); + max_session_memory_ = opts.max_session_memory(); - uint32_t maxHeaderPairs = opts.GetMaxHeaderPairs(); + uint32_t maxHeaderPairs = opts.max_header_pairs(); max_header_pairs_ = type == NGHTTP2_SESSION_SERVER ? GetServerMaxHeaderPairs(maxHeaderPairs) : GetClientMaxHeaderPairs(maxHeaderPairs); - max_outstanding_pings_ = opts.GetMaxOutstandingPings(); - max_outstanding_settings_ = opts.GetMaxOutstandingSettings(); + max_outstanding_pings_ = opts.max_outstanding_pings(); + max_outstanding_settings_ = opts.max_outstanding_settings(); - padding_strategy_ = opts.GetPaddingStrategy(); + padding_strategy_ = opts.padding_strategy(); bool hasGetPaddingCallback = padding_strategy_ != PADDING_STRATEGY_NONE; @@ -525,7 +510,7 @@ Http2Session::Http2Session(Http2State* http2_state, } Http2Session::~Http2Session() { - CHECK_EQ(flags_ & SESSION_STATE_HAS_SCOPE, 0); + CHECK(!is_in_scope()); Debug(this, "freeing nghttp2 session"); // Explicitly reset session_ so the subsequent // current_nghttp2_memory_ check passes. @@ -533,16 +518,23 @@ Http2Session::~Http2Session() { CHECK_EQ(current_nghttp2_memory_, 0); } +void Http2Session::MemoryInfo(MemoryTracker* tracker) const { + tracker->TrackField("streams", streams_); + tracker->TrackField("outstanding_pings", outstanding_pings_); + tracker->TrackField("outstanding_settings", outstanding_settings_); + tracker->TrackField("outgoing_buffers", outgoing_buffers_); + tracker->TrackFieldWithSize("stream_buf", stream_buf_.len); + tracker->TrackFieldWithSize("outgoing_storage", outgoing_storage_.size()); + tracker->TrackFieldWithSize("pending_rst_streams", + pending_rst_streams_.size() * sizeof(int32_t)); + tracker->TrackFieldWithSize("nghttp2_memory", current_nghttp2_memory_); +} + std::string Http2Session::diagnostic_name() const { return std::string("Http2Session ") + TypeName() + " (" + std::to_string(static_cast(get_async_id())) + ")"; } -inline bool HasHttp2Observer(Environment* env) { - AliasedUint32Array& observers = env->performance_state()->observers; - return observers[performance::NODE_PERFORMANCE_ENTRY_TYPE_HTTP2] != 0; -} - void Http2Stream::EmitStatistics() { CHECK_NOT_NULL(session()); if (!HasHttp2Observer(env())) @@ -615,13 +607,13 @@ void Http2Session::EmitStatistics() { void Http2Session::Close(uint32_t code, bool socket_closed) { Debug(this, "closing session"); - if (flags_ & SESSION_STATE_CLOSING) + if (is_closing()) return; - flags_ |= SESSION_STATE_CLOSING; + set_closing(); // Stop reading on the i/o stream if (stream_ != nullptr) { - flags_ |= SESSION_STATE_READING_STOPPED; + set_reading_stopped(); stream_->ReadStop(); } @@ -637,10 +629,10 @@ void Http2Session::Close(uint32_t code, bool socket_closed) { stream_->RemoveStreamListener(this); } - flags_ |= SESSION_STATE_CLOSED; + set_destroyed(); // If we are writing we will get to make the callback in OnStreamAfterWrite. - if ((flags_ & SESSION_STATE_WRITE_IN_PROGRESS) == 0) { + if (!is_write_in_progress()) { Debug(this, "make done session callback"); HandleScope scope(env()->isolate()); MakeCallback(env()->ondone_string(), 0, nullptr); @@ -663,12 +655,12 @@ void Http2Session::Close(uint32_t code, bool socket_closed) { // Locates an existing known stream by ID. nghttp2 has a similar method // but this is faster and does not fail if the stream is not found. -inline Http2Stream* Http2Session::FindStream(int32_t id) { +BaseObjectPtr Http2Session::FindStream(int32_t id) { auto s = streams_.find(id); - return s != streams_.end() ? s->second : nullptr; + return s != streams_.end() ? s->second : BaseObjectPtr(); } -inline bool Http2Session::CanAddStream() { +bool Http2Session::CanAddStream() { uint32_t maxConcurrentStreams = nghttp2_session_get_local_settings( session_.get(), NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS); @@ -677,12 +669,12 @@ inline bool Http2Session::CanAddStream() { // We can add a new stream so long as we are less than the current // maximum on concurrent streams and there's enough available memory return streams_.size() < maxSize && - IsAvailableSessionMemory(sizeof(Http2Stream)); + has_available_session_memory(sizeof(Http2Stream)); } -inline void Http2Session::AddStream(Http2Stream* stream) { +void Http2Session::AddStream(Http2Stream* stream) { CHECK_GE(++statistics_.stream_count, 0); - streams_[stream->id()] = stream; + streams_[stream->id()] = BaseObjectPtr(stream); size_t size = streams_.size(); if (size > statistics_.max_concurrent_streams) statistics_.max_concurrent_streams = size; @@ -690,11 +682,16 @@ inline void Http2Session::AddStream(Http2Stream* stream) { } -inline void Http2Session::RemoveStream(Http2Stream* stream) { - if (streams_.empty() || stream == nullptr) - return; // Nothing to remove, item was never added? - streams_.erase(stream->id()); - DecrementCurrentSessionMemory(sizeof(*stream)); +BaseObjectPtr Http2Session::RemoveStream(int32_t id) { + BaseObjectPtr stream; + if (streams_.empty()) + return stream; + stream = FindStream(id); + if (stream) { + streams_.erase(id); + DecrementCurrentSessionMemory(sizeof(*stream)); + } + return stream; } // Used as one of the Padding Strategy functions. Will attempt to ensure @@ -738,7 +735,7 @@ ssize_t Http2Session::ConsumeHTTP2Data() { Debug(this, "receiving %d bytes [wants data? %d]", read_len, nghttp2_session_want_read(session_.get())); - flags_ &= ~SESSION_STATE_NGHTTP2_RECV_PAUSED; + set_receive_paused(false); ssize_t ret = nghttp2_session_mem_recv(session_.get(), reinterpret_cast(stream_buf_.base) + @@ -746,8 +743,8 @@ ssize_t Http2Session::ConsumeHTTP2Data() { read_len); CHECK_NE(ret, NGHTTP2_ERR_NOMEM); - if (flags_ & SESSION_STATE_NGHTTP2_RECV_PAUSED) { - CHECK_NE(flags_ & SESSION_STATE_READING_STOPPED, 0); + if (is_receive_paused()) { + CHECK(is_reading_stopped()); CHECK_GT(ret, 0); CHECK_LE(static_cast(ret), read_len); @@ -770,14 +767,14 @@ ssize_t Http2Session::ConsumeHTTP2Data() { return ret; // Send any data that was queued up while processing the received data. - if (!IsDestroyed()) { + if (!is_destroyed()) { SendPendingData(); } return ret; } -inline int32_t GetFrameID(const nghttp2_frame* frame) { +int32_t GetFrameID(const nghttp2_frame* frame) { // If this is a push promise, we want to grab the id of the promised stream return (frame->hd.type == NGHTTP2_PUSH_PROMISE) ? frame->push_promise.promised_stream_id : @@ -796,10 +793,10 @@ int Http2Session::OnBeginHeadersCallback(nghttp2_session* handle, int32_t id = GetFrameID(frame); Debug(session, "beginning headers for stream %d", id); - Http2Stream* stream = session->FindStream(id); + BaseObjectPtr stream = session->FindStream(id); // The common case is that we're creating a new stream. The less likely // case is that we're receiving a set of trailers - if (LIKELY(stream == nullptr)) { + if (LIKELY(!stream)) { if (UNLIKELY(!session->CanAddStream() || Http2Stream::New(session, id, frame->headers.cat) == nullptr)) { @@ -807,13 +804,16 @@ int Http2Session::OnBeginHeadersCallback(nghttp2_session* handle, session->js_fields_->max_rejected_streams) return NGHTTP2_ERR_CALLBACK_FAILURE; // Too many concurrent streams being opened - nghttp2_submit_rst_stream(**session, NGHTTP2_FLAG_NONE, id, - NGHTTP2_ENHANCE_YOUR_CALM); + nghttp2_submit_rst_stream( + session->session(), + NGHTTP2_FLAG_NONE, + id, + NGHTTP2_ENHANCE_YOUR_CALM); return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; } session->rejected_stream_count_ = 0; - } else if (!stream->IsDestroyed()) { + } else if (!stream->is_destroyed()) { stream->StartHeaders(frame->headers.cat); } return 0; @@ -830,15 +830,15 @@ int Http2Session::OnHeaderCallback(nghttp2_session* handle, void* user_data) { Http2Session* session = static_cast(user_data); int32_t id = GetFrameID(frame); - Http2Stream* stream = session->FindStream(id); + BaseObjectPtr stream = session->FindStream(id); // If stream is null at this point, either something odd has happened // or the stream was closed locally while header processing was occurring. // either way, do not proceed and close the stream. - if (UNLIKELY(stream == nullptr)) + if (UNLIKELY(!stream)) return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; // If the stream has already been destroyed, ignore. - if (!stream->IsDestroyed() && !stream->AddHeader(name, value, flags)) { + if (!stream->is_destroyed() && !stream->AddHeader(name, value, flags)) { // This will only happen if the connected peer sends us more // than the allowed number of header items at any given time stream->SubmitRstStream(NGHTTP2_ENHANCE_YOUR_CALM); @@ -976,10 +976,10 @@ int Http2Session::OnStreamClose(nghttp2_session* handle, Local context = env->context(); Context::Scope context_scope(context); Debug(session, "stream %d closed with code: %d", id, code); - Http2Stream* stream = session->FindStream(id); + BaseObjectPtr stream = session->FindStream(id); // Intentionally ignore the callback if the stream does not exist or has // already been destroyed - if (stream == nullptr || stream->IsDestroyed()) + if (!stream || stream->is_destroyed()) return 0; stream->Close(code); @@ -991,6 +991,7 @@ int Http2Session::OnStreamClose(nghttp2_session* handle, MaybeLocal answer = stream->MakeCallback(env->http2session_on_stream_close_function(), 1, &arg); + Local def = v8::False(env->isolate()); if (answer.IsEmpty() || answer.ToLocalChecked()->IsFalse()) { // Skip to destroy stream->Destroy(); @@ -1037,9 +1038,10 @@ int Http2Session::OnDataChunkReceived(nghttp2_session* handle, // so that it can send a WINDOW_UPDATE frame. This is a critical part of // the flow control process in http2 CHECK_EQ(nghttp2_session_consume_connection(handle, len), 0); - Http2Stream* stream = session->FindStream(id); + BaseObjectPtr stream = session->FindStream(id); + // If the stream has been destroyed, ignore this chunk - if (stream->IsDestroyed()) + if (!stream || stream->is_destroyed()) return 0; stream->statistics_.received_bytes += len; @@ -1071,7 +1073,7 @@ int Http2Session::OnDataChunkReceived(nghttp2_session* handle, // If the stream owner (e.g. the JS Http2Stream) wants more data, just // tell nghttp2 that all data has been consumed. Otherwise, defer until // more data is being requested. - if (stream->IsReading()) + if (stream->is_reading()) nghttp2_session_consume_stream(handle, id, avail); else stream->inbound_consumed_data_while_paused_ += avail; @@ -1085,9 +1087,9 @@ int Http2Session::OnDataChunkReceived(nghttp2_session* handle, // If we are currently waiting for a write operation to finish, we should // tell nghttp2 that we want to wait before we process more input data. - if (session->flags_ & SESSION_STATE_WRITE_IN_PROGRESS) { - CHECK_NE(session->flags_ & SESSION_STATE_READING_STOPPED, 0); - session->flags_ |= SESSION_STATE_NGHTTP2_RECV_PAUSED; + if (session->is_write_in_progress()) { + CHECK(session->is_reading_stopped()); + session->set_receive_paused(); return NGHTTP2_ERR_PAUSE; } @@ -1194,10 +1196,10 @@ void Http2Session::HandleHeadersFrame(const nghttp2_frame* frame) { int32_t id = GetFrameID(frame); Debug(this, "handle headers frame for stream %d", id); - Http2Stream* stream = FindStream(id); + BaseObjectPtr stream = FindStream(id); // If the stream has already been destroyed, ignore. - if (stream->IsDestroyed()) + if (!stream || stream->is_destroyed()) return; // The headers are stored as a vector of Http2Header instances. @@ -1263,9 +1265,11 @@ void Http2Session::HandlePriorityFrame(const nghttp2_frame* frame) { int Http2Session::HandleDataFrame(const nghttp2_frame* frame) { int32_t id = GetFrameID(frame); Debug(this, "handling data frame for stream %d", id); - Http2Stream* stream = FindStream(id); + BaseObjectPtr stream = FindStream(id); - if (!stream->IsDestroyed() && frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { + if (stream && + !stream->is_destroyed() && + frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { stream->EmitRead(UV_EOF); } else if (frame->hd.length == 0) { return 1; // Consider 0-length frame without END_STREAM an error. @@ -1292,6 +1296,9 @@ void Http2Session::HandleGoawayFrame(const nghttp2_frame* frame) { size_t length = goaway_frame.opaque_data_len; if (length > 0) { + // If the copy fails for any reason here, we just ignore it. + // The additional goaway data is completely optional and we + // shouldn't fail if we're not able to process it. argv[2] = Buffer::Copy(isolate, reinterpret_cast(goaway_frame.opaque_data), length).ToLocalChecked(); @@ -1317,14 +1324,8 @@ void Http2Session::HandleAltSvcFrame(const nghttp2_frame* frame) { Local argv[3] = { Integer::New(isolate, id), - String::NewFromOneByte(isolate, - altsvc->origin, - NewStringType::kNormal, - altsvc->origin_len).ToLocalChecked(), - String::NewFromOneByte(isolate, - altsvc->field_value, - NewStringType::kNormal, - altsvc->field_value_len).ToLocalChecked(), + OneByteString(isolate, altsvc->origin, altsvc->origin_len), + OneByteString(isolate, altsvc->field_value, altsvc->field_value_len) }; MakeCallback(env()->http2session_on_altsvc_function(), @@ -1347,10 +1348,7 @@ void Http2Session::HandleOriginFrame(const nghttp2_frame* frame) { for (size_t i = 0; i < nov; ++i) { const nghttp2_origin_entry& entry = origin->ov[i]; - origin_v[i] = - String::NewFromOneByte( - isolate, entry.origin, NewStringType::kNormal, entry.origin_len) - .ToLocalChecked(); + origin_v[i] = OneByteString(isolate, entry.origin, entry.origin_len); } Local holder = Array::New(isolate, origin_v.data(), origin_v.size()); MakeCallback(env()->http2session_on_origin_function(), 1, &holder); @@ -1384,9 +1382,10 @@ void Http2Session::HandlePingFrame(const nghttp2_frame* frame) { if (!(js_fields_->bitfield & (1 << kSessionHasPingListeners))) return; // Notify the session that a ping occurred - arg = Buffer::Copy(env(), - reinterpret_cast(frame->ping.opaque_data), - 8).ToLocalChecked(); + arg = Buffer::Copy( + env(), + reinterpret_cast(frame->ping.opaque_data), + 8).ToLocalChecked(); MakeCallback(env()->http2session_on_ping_function(), 1, &arg); } @@ -1430,20 +1429,20 @@ void Http2Session::HandleSettingsFrame(const nghttp2_frame* frame) { void Http2Session::OnStreamAfterWrite(WriteWrap* w, int status) { Debug(this, "write finished with status %d", status); - CHECK_NE(flags_ & SESSION_STATE_WRITE_IN_PROGRESS, 0); - flags_ &= ~SESSION_STATE_WRITE_IN_PROGRESS; + CHECK(is_write_in_progress()); + set_write_in_progress(false); // Inform all pending writes about their completion. ClearOutgoing(status); - if ((flags_ & SESSION_STATE_READING_STOPPED) && - !(flags_ & SESSION_STATE_WRITE_IN_PROGRESS) && + if (is_reading_stopped() && + !is_write_in_progress() && nghttp2_session_want_read(session_.get())) { - flags_ &= ~SESSION_STATE_READING_STOPPED; + set_reading_stopped(false); stream_->ReadStart(); } - if ((flags_ & SESSION_STATE_CLOSED) != 0) { + if (is_destroyed()) { HandleScope scope(env()->isolate()); MakeCallback(env()->ondone_string(), 0, nullptr); return; @@ -1454,7 +1453,7 @@ void Http2Session::OnStreamAfterWrite(WriteWrap* w, int status) { ConsumeHTTP2Data(); } - if (!(flags_ & SESSION_STATE_WRITE_SCHEDULED)) { + if (!is_write_scheduled()) { // Schedule a new write if nghttp2 wants to send data. MaybeScheduleWrite(); } @@ -1465,17 +1464,17 @@ void Http2Session::OnStreamAfterWrite(WriteWrap* w, int status) { // on the next iteration of the Node.js event loop (using the SetImmediate // queue), but only if a write has not already been scheduled. void Http2Session::MaybeScheduleWrite() { - CHECK_EQ(flags_ & SESSION_STATE_WRITE_SCHEDULED, 0); + CHECK(!is_write_scheduled()); if (UNLIKELY(!session_)) return; if (nghttp2_session_want_write(session_.get())) { HandleScope handle_scope(env()->isolate()); Debug(this, "scheduling write"); - flags_ |= SESSION_STATE_WRITE_SCHEDULED; + set_write_scheduled(); BaseObjectPtr strong_ref{this}; env()->SetImmediate([this, strong_ref](Environment* env) { - if (!session_ || !(flags_ & SESSION_STATE_WRITE_SCHEDULED)) { + if (!session_ || !is_write_scheduled()) { // This can happen e.g. when a stream was reset before this turn // of the event loop, in which case SendPendingData() is called early, // or the session was destroyed in the meantime. @@ -1492,11 +1491,11 @@ void Http2Session::MaybeScheduleWrite() { } void Http2Session::MaybeStopReading() { - if (flags_ & SESSION_STATE_READING_STOPPED) return; + if (is_reading_stopped()) return; int want_read = nghttp2_session_want_read(session_.get()); Debug(this, "wants read? %d", want_read); - if (want_read == 0 || (flags_ & SESSION_STATE_WRITE_IN_PROGRESS)) { - flags_ |= SESSION_STATE_READING_STOPPED; + if (want_read == 0 || is_write_in_progress()) { + set_reading_stopped(); stream_->ReadStop(); } } @@ -1504,9 +1503,9 @@ void Http2Session::MaybeStopReading() { // Unset the sending state, finish up all current writes, and reset // storage for data and metadata that was associated with these writes. void Http2Session::ClearOutgoing(int status) { - CHECK_NE(flags_ & SESSION_STATE_SENDING, 0); + CHECK(is_sending()); - flags_ &= ~SESSION_STATE_SENDING; + set_sending(false); if (outgoing_buffers_.size() > 0) { outgoing_storage_.clear(); @@ -1534,8 +1533,8 @@ void Http2Session::ClearOutgoing(int status) { SendPendingData(); for (int32_t stream_id : current_pending_rst_streams) { - Http2Stream* stream = FindStream(stream_id); - if (LIKELY(stream != nullptr)) + BaseObjectPtr stream = FindStream(stream_id); + if (LIKELY(stream)) stream->FlushRstStream(); } } @@ -1573,15 +1572,15 @@ uint8_t Http2Session::SendPendingData() { // Do not attempt to send data on the socket if the destroying flag has // been set. That means everything is shutting down and the socket // will not be usable. - if (IsDestroyed()) + if (is_destroyed()) return 0; - flags_ &= ~SESSION_STATE_WRITE_SCHEDULED; + set_write_scheduled(false); // SendPendingData should not be called recursively. - if (flags_ & SESSION_STATE_SENDING) + if (is_sending()) return 1; // This is cleared by ClearOutgoing(). - flags_ |= SESSION_STATE_SENDING; + set_sending(); ssize_t src_length; const uint8_t* src; @@ -1635,11 +1634,11 @@ uint8_t Http2Session::SendPendingData() { chunks_sent_since_last_write_++; - CHECK_EQ(flags_ & SESSION_STATE_WRITE_IN_PROGRESS, 0); - flags_ |= SESSION_STATE_WRITE_IN_PROGRESS; + CHECK(!is_write_in_progress()); + set_write_in_progress(); StreamWriteResult res = underlying_stream()->Write(*bufs, count); if (!res.async) { - flags_ &= ~SESSION_STATE_WRITE_IN_PROGRESS; + set_write_in_progress(false); ClearOutgoing(res.err); } @@ -1661,7 +1660,8 @@ int Http2Session::OnSendData( nghttp2_data_source* source, void* user_data) { Http2Session* session = static_cast(user_data); - Http2Stream* stream = GetStream(session, frame->hd.stream_id, source); + BaseObjectPtr stream = session->FindStream(frame->hd.stream_id); + if (!stream) return 0; // Send the frame header + a byte that indicates padding length. session->CopyDataIntoOutgoing(framehd, 9); @@ -1707,7 +1707,7 @@ int Http2Session::OnSendData( // Creates a new Http2Stream and submits a new http2 request. Http2Stream* Http2Session::SubmitRequest( - nghttp2_priority_spec* prispec, + const Http2Priority& priority, const Http2Headers& headers, int32_t* ret, int options) { @@ -1717,7 +1717,7 @@ Http2Stream* Http2Session::SubmitRequest( Http2Stream::Provider::Stream prov(options); *ret = nghttp2_submit_request( session_.get(), - prispec, + &priority, headers.data(), headers.length(), *prov, @@ -1768,6 +1768,9 @@ void Http2Session::OnStreamRead(ssize_t nread, const uv_buf_t& buf_) { // The data in stream_buf_ is already accounted for, add nread received // bytes to session memory but remove the already processed // stream_buf_offset_ bytes. + // TODO(@jasnell): There are some cases where nread is < stream_buf_offset_ + // here but things still work. Those need to be investigated. + // CHECK_GE(nread, stream_buf_offset_); IncrementCurrentSessionMemory(nread - stream_buf_offset_); buf = std::move(new_buf); @@ -1846,7 +1849,7 @@ Http2Stream::Http2Stream(Http2Session* session, statistics_.start_time = uv_hrtime(); // Limit the number of header pairs - max_header_pairs_ = session->GetMaxHeaderPairs(); + max_header_pairs_ = session->max_header_pairs(); if (max_header_pairs_ == 0) { max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS; } @@ -1861,7 +1864,7 @@ Http2Stream::Http2Stream(Http2Session* session, MAX_MAX_HEADER_LIST_SIZE); if (options & STREAM_OPTION_GET_TRAILERS) - flags_ |= NGHTTP2_STREAM_FLAG_TRAILERS; + set_has_trailers(); PushStreamListener(&stream_listener_); @@ -1871,11 +1874,12 @@ Http2Stream::Http2Stream(Http2Session* session, } Http2Stream::~Http2Stream() { - if (!session_) - return; Debug(this, "tearing down stream"); - session_->DecrementCurrentSessionMemory(current_headers_length_); - session_->RemoveStream(this); +} + +void Http2Stream::MemoryInfo(MemoryTracker* tracker) const { + tracker->TrackField("current_headers", current_headers_); + tracker->TrackField("queue", queue_); } std::string Http2Stream::diagnostic_name() const { @@ -1887,7 +1891,7 @@ std::string Http2Stream::diagnostic_name() const { // Notify the Http2Stream that a new block of HEADERS is being processed. void Http2Stream::StartHeaders(nghttp2_headers_category category) { Debug(this, "starting headers, category: %d", category); - CHECK(!this->IsDestroyed()); + CHECK(!this->is_destroyed()); session_->DecrementCurrentSessionMemory(current_headers_length_); current_headers_length_ = 0; current_headers_.clear(); @@ -1895,13 +1899,15 @@ void Http2Stream::StartHeaders(nghttp2_headers_category category) { } -nghttp2_stream* Http2Stream::operator*() { - return nghttp2_session_find_stream(**session_, id_); +nghttp2_stream* Http2Stream::operator*() const { return stream(); } + +nghttp2_stream* Http2Stream::stream() const { + return nghttp2_session_find_stream(session_->session(), id_); } void Http2Stream::Close(int32_t code) { - CHECK(!this->IsDestroyed()); - flags_ |= NGHTTP2_STREAM_FLAG_CLOSED; + CHECK(!this->is_destroyed()); + set_closed(); code_ = code; Debug(this, "closed with code %d", code); } @@ -1913,14 +1919,15 @@ ShutdownWrap* Http2Stream::CreateShutdownWrap(v8::Local object) { } int Http2Stream::DoShutdown(ShutdownWrap* req_wrap) { - if (IsDestroyed()) + if (is_destroyed()) return UV_EPIPE; { Http2Scope h2scope(this); - flags_ |= NGHTTP2_STREAM_FLAG_SHUT; - CHECK_NE(nghttp2_session_resume_data(**session_, id_), - NGHTTP2_ERR_NOMEM); + set_not_writable(); + CHECK_NE(nghttp2_session_resume_data( + session_->session(), id_), + NGHTTP2_ERR_NOMEM); Debug(this, "writable side shutdown"); } return 1; @@ -1931,36 +1938,40 @@ int Http2Stream::DoShutdown(ShutdownWrap* req_wrap) { // using the SetImmediate queue. void Http2Stream::Destroy() { // Do nothing if this stream instance is already destroyed - if (IsDestroyed()) + if (is_destroyed()) return; - if (session_->HasPendingRstStream(id_)) + if (session_->has_pending_rststream(id_)) FlushRstStream(); - flags_ |= NGHTTP2_STREAM_FLAG_DESTROYED; + set_destroyed(); Debug(this, "destroying stream"); // Wait until the start of the next loop to delete because there // may still be some pending operations queued for this stream. - BaseObjectPtr strong_ref{this}; - env()->SetImmediate([this, strong_ref](Environment* env) { - // Free any remaining outgoing data chunks here. This should be done - // here because it's possible for destroy to have been called while - // we still have queued outbound writes. - while (!queue_.empty()) { - NgHttp2StreamWrite& head = queue_.front(); - if (head.req_wrap != nullptr) - head.req_wrap->Done(UV_ECANCELED); - queue_.pop(); - } + BaseObjectPtr strong_ref = session_->RemoveStream(id_); + if (strong_ref) { + env()->SetImmediate([this, strong_ref = std::move(strong_ref)]( + Environment* env) { + // Free any remaining outgoing data chunks here. This should be done + // here because it's possible for destroy to have been called while + // we still have queued outbound writes. + while (!queue_.empty()) { + NgHttp2StreamWrite& head = queue_.front(); + if (head.req_wrap != nullptr) + head.req_wrap->Done(UV_ECANCELED); + queue_.pop(); + } - // We can destroy the stream now if there are no writes for it - // already on the socket. Otherwise, we'll wait for the garbage collector - // to take care of cleaning up. - if (session() == nullptr || !session()->HasWritesOnSocketForStream(this)) { - // Delete once strong_ref goes out of scope. - Detach(); - } - }); + // We can destroy the stream now if there are no writes for it + // already on the socket. Otherwise, we'll wait for the garbage collector + // to take care of cleaning up. + if (session() == nullptr || + !session()->HasWritesOnSocketForStream(this)) { + // Delete once strong_ref goes out of scope. + Detach(); + } + }); + } statistics_.end_time = uv_hrtime(); session_->statistics_.stream_average_duration = @@ -1973,18 +1984,18 @@ void Http2Stream::Destroy() { // Initiates a response on the Http2Stream using data provided via the // StreamBase Streams API. int Http2Stream::SubmitResponse(const Http2Headers& headers, int options) { - CHECK(!this->IsDestroyed()); + CHECK(!this->is_destroyed()); Http2Scope h2scope(this); Debug(this, "submitting response"); if (options & STREAM_OPTION_GET_TRAILERS) - flags_ |= NGHTTP2_STREAM_FLAG_TRAILERS; + set_has_trailers(); - if (!IsWritable()) + if (!is_writable()) options |= STREAM_OPTION_EMPTY_PAYLOAD; Http2Stream::Provider::Stream prov(this, options); int ret = nghttp2_submit_response( - **session_, + session_->session(), id_, headers.data(), headers.length(), @@ -1996,11 +2007,11 @@ int Http2Stream::SubmitResponse(const Http2Headers& headers, int options) { // Submit informational headers for a stream. int Http2Stream::SubmitInfo(const Http2Headers& headers) { - CHECK(!this->IsDestroyed()); + CHECK(!this->is_destroyed()); Http2Scope h2scope(this); Debug(this, "sending %d informational headers", headers.length()); int ret = nghttp2_submit_headers( - **session_, + session_->session(), NGHTTP2_FLAG_NONE, id_, nullptr, @@ -2013,18 +2024,18 @@ int Http2Stream::SubmitInfo(const Http2Headers& headers) { void Http2Stream::OnTrailers() { Debug(this, "let javascript know we are ready for trailers"); - CHECK(!this->IsDestroyed()); + CHECK(!this->is_destroyed()); Isolate* isolate = env()->isolate(); HandleScope scope(isolate); Local context = env()->context(); Context::Scope context_scope(context); - flags_ &= ~NGHTTP2_STREAM_FLAG_TRAILERS; + set_has_trailers(false); MakeCallback(env()->http2session_on_stream_trailers_function(), 0, nullptr); } // Submit informational headers for a stream. int Http2Stream::SubmitTrailers(const Http2Headers& headers) { - CHECK(!this->IsDestroyed()); + CHECK(!this->is_destroyed()); Http2Scope h2scope(this); Debug(this, "sending %d trailers", headers.length()); int ret; @@ -2033,10 +2044,14 @@ int Http2Stream::SubmitTrailers(const Http2Headers& headers) { // to indicate that the stream is ready to be closed. if (headers.length() == 0) { Http2Stream::Provider::Stream prov(this, 0); - ret = nghttp2_submit_data(**session_, NGHTTP2_FLAG_END_STREAM, id_, *prov); + ret = nghttp2_submit_data( + session_->session(), + NGHTTP2_FLAG_END_STREAM, + id_, + *prov); } else { ret = nghttp2_submit_trailer( - **session_, + session_->session(), id_, headers.data(), headers.length()); @@ -2046,17 +2061,20 @@ int Http2Stream::SubmitTrailers(const Http2Headers& headers) { } // Submit a PRIORITY frame to the connected peer. -int Http2Stream::SubmitPriority(nghttp2_priority_spec* prispec, +int Http2Stream::SubmitPriority(const Http2Priority& priority, bool silent) { - CHECK(!this->IsDestroyed()); + CHECK(!this->is_destroyed()); Http2Scope h2scope(this); Debug(this, "sending priority spec"); int ret = silent ? - nghttp2_session_change_stream_priority(**session_, - id_, prispec) : - nghttp2_submit_priority(**session_, - NGHTTP2_FLAG_NONE, - id_, prispec); + nghttp2_session_change_stream_priority( + session_->session(), + id_, + &priority) : + nghttp2_submit_priority( + session_->session(), + NGHTTP2_FLAG_NONE, + id_, &priority); CHECK_NE(ret, NGHTTP2_ERR_NOMEM); return ret; } @@ -2064,7 +2082,7 @@ int Http2Stream::SubmitPriority(nghttp2_priority_spec* prispec, // Closes the Http2Stream by submitting an RST_STREAM frame to the connected // peer. void Http2Stream::SubmitRstStream(const uint32_t code) { - CHECK(!this->IsDestroyed()); + CHECK(!this->is_destroyed()); code_ = code; // If possible, force a purge of any currently pending data here to make sure // it is sent before closing the stream. If it returns non-zero then we need @@ -2079,11 +2097,14 @@ void Http2Stream::SubmitRstStream(const uint32_t code) { } void Http2Stream::FlushRstStream() { - if (IsDestroyed()) + if (is_destroyed()) return; Http2Scope h2scope(this); - CHECK_EQ(nghttp2_submit_rst_stream(**session_, NGHTTP2_FLAG_NONE, - id_, code_), 0); + CHECK_EQ(nghttp2_submit_rst_stream( + session_->session(), + NGHTTP2_FLAG_NONE, + id_, + code_), 0); } @@ -2091,11 +2112,11 @@ void Http2Stream::FlushRstStream() { Http2Stream* Http2Stream::SubmitPushPromise(const Http2Headers& headers, int32_t* ret, int options) { - CHECK(!this->IsDestroyed()); + CHECK(!this->is_destroyed()); Http2Scope h2scope(this); Debug(this, "sending push promise"); *ret = nghttp2_submit_push_promise( - **session_, + session_->session(), NGHTTP2_FLAG_NONE, id_, headers.data(), @@ -2115,17 +2136,17 @@ Http2Stream* Http2Stream::SubmitPushPromise(const Http2Headers& headers, // out to JS land. int Http2Stream::ReadStart() { Http2Scope h2scope(this); - CHECK(!this->IsDestroyed()); - flags_ |= NGHTTP2_STREAM_FLAG_READ_START; - flags_ &= ~NGHTTP2_STREAM_FLAG_READ_PAUSED; + CHECK(!this->is_destroyed()); + set_reading(); Debug(this, "reading starting"); // Tell nghttp2 about our consumption of the data that was handed // off to JS land. - nghttp2_session_consume_stream(**session_, - id_, - inbound_consumed_data_while_paused_); + nghttp2_session_consume_stream( + session_->session(), + id_, + inbound_consumed_data_while_paused_); inbound_consumed_data_while_paused_ = 0; return 0; @@ -2133,10 +2154,10 @@ int Http2Stream::ReadStart() { // Switch the StreamBase into paused mode. int Http2Stream::ReadStop() { - CHECK(!this->IsDestroyed()); - if (!IsReading()) + CHECK(!this->is_destroyed()); + if (!is_reading()) return 0; - flags_ |= NGHTTP2_STREAM_FLAG_READ_PAUSED; + set_paused(); Debug(this, "reading stopped"); return 0; } @@ -2157,7 +2178,7 @@ int Http2Stream::DoWrite(WriteWrap* req_wrap, uv_stream_t* send_handle) { CHECK_NULL(send_handle); Http2Scope h2scope(this); - if (!IsWritable() || IsDestroyed()) { + if (!is_writable() || is_destroyed()) { req_wrap->Done(UV_EOF); return 0; } @@ -2171,7 +2192,9 @@ int Http2Stream::DoWrite(WriteWrap* req_wrap, }); IncrementAvailableOutboundLength(bufs[i].len); } - CHECK_NE(nghttp2_session_resume_data(**session_, id_), NGHTTP2_ERR_NOMEM); + CHECK_NE(nghttp2_session_resume_data( + session_->session(), + id_), NGHTTP2_ERR_NOMEM); return 0; } @@ -2183,7 +2206,7 @@ int Http2Stream::DoWrite(WriteWrap* req_wrap, bool Http2Stream::AddHeader(nghttp2_rcbuf* name, nghttp2_rcbuf* value, uint8_t flags) { - CHECK(!this->IsDestroyed()); + CHECK(!this->is_destroyed()); if (Http2RcBufferPointer::IsZeroLength(name)) return true; // Ignore empty headers. @@ -2192,7 +2215,7 @@ bool Http2Stream::AddHeader(nghttp2_rcbuf* name, size_t length = header.length() + 32; // A header can only be added if we have not exceeded the maximum number // of headers and the session has memory available for it. - if (!session_->IsAvailableSessionMemory(length) || + if (!session_->has_available_session_memory(length) || current_headers_.size() == max_header_pairs_ || current_headers_length_ + length > max_header_length_) { return false; @@ -2210,7 +2233,7 @@ bool Http2Stream::AddHeader(nghttp2_rcbuf* name, // A Provider is the thing that provides outbound DATA frame data. Http2Stream::Provider::Provider(Http2Stream* stream, int options) { - CHECK(!stream->IsDestroyed()); + CHECK(!stream->is_destroyed()); provider_.source.ptr = stream; empty_ = options & STREAM_OPTION_EMPTY_PAYLOAD; } @@ -2245,7 +2268,8 @@ ssize_t Http2Stream::Provider::Stream::OnRead(nghttp2_session* handle, void* user_data) { Http2Session* session = static_cast(user_data); Debug(session, "reading outbound data for stream %d", id); - Http2Stream* stream = GetStream(session, id, source); + BaseObjectPtr stream = session->FindStream(id); + if (!stream) return 0; if (stream->statistics_.first_byte_sent == 0) stream->statistics_.first_byte_sent = uv_hrtime(); CHECK_EQ(id, stream->id()); @@ -2275,21 +2299,21 @@ ssize_t Http2Stream::Provider::Stream::OnRead(nghttp2_session* handle, } } - if (amount == 0 && stream->IsWritable()) { + if (amount == 0 && stream->is_writable()) { CHECK(stream->queue_.empty()); Debug(session, "deferring stream %d", id); stream->EmitWantsWrite(length); - if (stream->available_outbound_length_ > 0 || !stream->IsWritable()) { + if (stream->available_outbound_length_ > 0 || !stream->is_writable()) { // EmitWantsWrite() did something interesting synchronously, restart: return OnRead(handle, id, buf, length, flags, source, user_data); } return NGHTTP2_ERR_DEFERRED; } - if (stream->queue_.empty() && !stream->IsWritable()) { + if (stream->queue_.empty() && !stream->is_writable()) { Debug(session, "no more data for stream %d", id); *flags |= NGHTTP2_DATA_FLAG_EOF; - if (stream->HasTrailers()) { + if (stream->has_trailers()) { *flags |= NGHTTP2_DATA_FLAG_NO_END_STREAM; stream->OnTrailers(); } @@ -2299,12 +2323,12 @@ ssize_t Http2Stream::Provider::Stream::OnRead(nghttp2_session* handle, return amount; } -inline void Http2Stream::IncrementAvailableOutboundLength(size_t amount) { +void Http2Stream::IncrementAvailableOutboundLength(size_t amount) { available_outbound_length_ += amount; session_->IncrementCurrentSessionMemory(amount); } -inline void Http2Stream::DecrementAvailableOutboundLength(size_t amount) { +void Http2Stream::DecrementAvailableOutboundLength(size_t amount) { available_outbound_length_ -= amount; session_->DecrementCurrentSessionMemory(amount); } @@ -2318,10 +2342,9 @@ void HttpErrorString(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); uint32_t val = args[0]->Uint32Value(env->context()).ToChecked(); args.GetReturnValue().Set( - String::NewFromOneByte( + OneByteString( env->isolate(), - reinterpret_cast(nghttp2_strerror(val)), - NewStringType::kInternalized).ToLocalChecked()); + reinterpret_cast(nghttp2_strerror(val)))); } @@ -2330,16 +2353,7 @@ void HttpErrorString(const FunctionCallbackInfo& args) { // output for an HTTP2-Settings header field. void PackSettings(const FunctionCallbackInfo& args) { Http2State* state = Unwrap(args.Data()); - Environment* env = state->env(); - // TODO(addaleax): We should not be creating a full AsyncWrap for this. - Local obj; - if (!env->http2settings_constructor_template() - ->NewInstance(env->context()) - .ToLocal(&obj)) { - return; - } - Http2Session::Http2Settings settings(state, nullptr, obj); - args.GetReturnValue().Set(settings.Pack()); + args.GetReturnValue().Set(Http2Settings::Pack(state)); } // A TypedArray instance is shared between C++ and JS land to contain the @@ -2347,7 +2361,7 @@ void PackSettings(const FunctionCallbackInfo& args) { // default values. void RefreshDefaultSettings(const FunctionCallbackInfo& args) { Http2State* state = Unwrap(args.Data()); - Http2Session::Http2Settings::RefreshDefaults(state); + Http2Settings::RefreshDefaults(state); } // Sets the next stream ID the Http2Session. If successful, returns true. @@ -2356,7 +2370,7 @@ void Http2Session::SetNextStreamID(const FunctionCallbackInfo& args) { Http2Session* session; ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder()); int32_t id = args[0]->Int32Value(env->context()).ToChecked(); - if (nghttp2_session_set_next_stream_id(**session, id) < 0) { + if (nghttp2_session_set_next_stream_id(session->session(), id) < 0) { Debug(session, "failed to set next stream id to %d", id); return args.GetReturnValue().Set(false); } @@ -2385,7 +2399,7 @@ void Http2Session::RefreshState(const FunctionCallbackInfo& args) { AliasedFloat64Array& buffer = session->http2_state()->session_state_buffer; - nghttp2_session* s = **session; + nghttp2_session* s = session->session(); buffer[IDX_SESSION_STATE_EFFECTIVE_LOCAL_WINDOW_SIZE] = nghttp2_session_get_effective_local_window_size(s); @@ -2413,8 +2427,9 @@ void Http2Session::New(const FunctionCallbackInfo& args) { Http2State* state = Unwrap(args.Data()); Environment* env = state->env(); CHECK(args.IsConstructCall()); - int32_t val = args[0]->Int32Value(env->context()).ToChecked(); - nghttp2_session_type type = static_cast(val); + SessionType type = + static_cast( + args[0]->Int32Value(env->context()).ToChecked()); Http2Session* session = new Http2Session(state, args.This(), type); session->get_async_id(); // avoid compiler warning Debug(session, "session created"); @@ -2450,14 +2465,13 @@ void Http2Session::Request(const FunctionCallbackInfo& args) { Local headers = args[0].As(); int32_t options = args[1]->Int32Value(env->context()).ToChecked(); - Http2Priority priority(env, args[2], args[3], args[4]); Debug(session, "request submitted"); int32_t ret = 0; Http2Stream* stream = session->Http2Session::SubmitRequest( - &priority, + Http2Priority(env, args[2], args[3], args[4]), Http2Headers(env, headers), &ret, static_cast(options)); @@ -2478,7 +2492,7 @@ void Http2Session::Goaway(uint32_t code, int32_t lastStreamID, const uint8_t* data, size_t len) { - if (IsDestroyed()) + if (is_destroyed()) return; Http2Scope h2scope(this); @@ -2629,10 +2643,9 @@ void Http2Stream::Priority(const FunctionCallbackInfo& args) { Http2Stream* stream; ASSIGN_OR_RETURN_UNWRAP(&stream, args.Holder()); - Http2Priority priority(env, args[0], args[1], args[2]); - bool silent = args[3]->IsTrue(); - - CHECK_EQ(stream->SubmitPriority(&priority, silent), 0); + CHECK_EQ(stream->SubmitPriority( + Http2Priority(env, args[0], args[1], args[2]), + args[3]->IsTrue()), 0); Debug(stream, "priority submitted"); } @@ -2649,8 +2662,8 @@ void Http2Stream::RefreshState(const FunctionCallbackInfo& args) { AliasedFloat64Array& buffer = stream->session()->http2_state()->stream_state_buffer; - nghttp2_stream* str = **stream; - nghttp2_session* s = **(stream->session()); + nghttp2_stream* str = stream->stream(); + nghttp2_session* s = stream->session()->session(); if (str == nullptr) { buffer[IDX_STREAM_STATE] = NGHTTP2_STREAM_STATE_IDLE; @@ -2685,12 +2698,13 @@ void Http2Session::AltSvc(int32_t id, origin, origin_len, value, value_len), 0); } -void Http2Session::Origin(nghttp2_origin_entry* ov, size_t count) { +void Http2Session::Origin(const Origins& origins) { Http2Scope h2scope(this); CHECK_EQ(nghttp2_submit_origin( session_.get(), NGHTTP2_FLAG_NONE, - ov, count), 0); + *origins, + origins.length()), 0); } // Submits an AltSvc frame to be sent to the connected peer. @@ -2705,6 +2719,9 @@ void Http2Session::AltSvc(const FunctionCallbackInfo& args) { Local origin_str = args[1]->ToString(env->context()).ToLocalChecked(); Local value_str = args[2]->ToString(env->context()).ToLocalChecked(); + if (origin_str.IsEmpty() || value_str.IsEmpty()) + return; + size_t origin_len = origin_str->Length(); size_t value_len = value_str->Length(); @@ -2728,15 +2745,9 @@ void Http2Session::Origin(const FunctionCallbackInfo& args) { ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder()); Local origin_string = args[0].As(); - int32_t count = args[1]->Int32Value(context).ToChecked(); - + size_t count = args[1]->Int32Value(context).ToChecked(); - Origins origins(env->isolate(), - env->context(), - origin_string, - static_cast(count)); - - session->Origin(*origins, origins.length()); + session->Origin(Origins(env, origin_string, count)); } // Submits a PING frame to be sent to the connected peer. @@ -2753,28 +2764,9 @@ void Http2Session::Ping(const FunctionCallbackInfo& args) { CHECK_EQ(payload.length(), 8); } - Local obj; - if (!env->http2ping_constructor_template() - ->NewInstance(env->context()) - .ToLocal(&obj)) { - return; - } - if (obj->Set(env->context(), env->ondone_string(), args[1]).IsNothing()) - return; - - Http2Ping* ping = session->AddPing( - MakeDetachedBaseObject(session, obj)); - // To prevent abuse, we strictly limit the number of unacknowledged PING - // frames that may be sent at any given time. This is configurable in the - // Options when creating a Http2Session. - if (ping == nullptr) return args.GetReturnValue().Set(false); - - // The Ping itself is an Async resource. When the acknowledgement is received, - // the callback will be invoked and a notification sent out to JS land. The - // notification will include the duration of the ping, allowing the round - // trip to be measured. - ping->Send(payload.data()); - args.GetReturnValue().Set(true); + CHECK(args[1]->IsFunction()); + args.GetReturnValue().Set( + session->AddPing(payload.data(), args[1].As())); } // Submits a SETTINGS frame for the Http2Session @@ -2782,26 +2774,11 @@ void Http2Session::Settings(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); Http2Session* session; ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder()); - - Local obj; - if (!env->http2settings_constructor_template() - ->NewInstance(env->context()) - .ToLocal(&obj)) { - return; - } - if (obj->Set(env->context(), env->ondone_string(), args[0]).IsNothing()) - return; - - Http2Settings* settings = session->AddSettings( - MakeDetachedBaseObject( - session->http2_state(), session, obj, 0)); - if (settings == nullptr) return args.GetReturnValue().Set(false); - - settings->Send(); - args.GetReturnValue().Set(true); + CHECK(args[0]->IsFunction()); + args.GetReturnValue().Set(session->AddSettings(args[0].As())); } -BaseObjectPtr Http2Session::PopPing() { +BaseObjectPtr Http2Session::PopPing() { BaseObjectPtr ping; if (!outstanding_pings_.empty()) { ping = std::move(outstanding_pings_.front()); @@ -2811,19 +2788,36 @@ BaseObjectPtr Http2Session::PopPing() { return ping; } -Http2Session::Http2Ping* Http2Session::AddPing( - BaseObjectPtr ping) { +bool Http2Session::AddPing(const uint8_t* payload, Local callback) { + Local obj; + if (!env()->http2ping_constructor_template() + ->NewInstance(env()->context()) + .ToLocal(&obj)) { + return false; + } + + BaseObjectPtr ping = + MakeDetachedBaseObject(this, obj, callback); + if (!ping) + return false; + if (outstanding_pings_.size() == max_outstanding_pings_) { ping->Done(false); - return nullptr; + return false; } - Http2Ping* ptr = ping.get(); - outstanding_pings_.emplace(std::move(ping)); + IncrementCurrentSessionMemory(sizeof(*ping)); - return ptr; + // The Ping itself is an Async resource. When the acknowledgement is received, + // the callback will be invoked and a notification sent out to JS land. The + // notification will include the duration of the ping, allowing the round + // trip to be measured. + ping->Send(payload); + + outstanding_pings_.emplace(std::move(ping)); + return true; } -BaseObjectPtr Http2Session::PopSettings() { +BaseObjectPtr Http2Session::PopSettings() { BaseObjectPtr settings; if (!outstanding_settings_.empty()) { settings = std::move(outstanding_settings_.front()); @@ -2833,60 +2827,88 @@ BaseObjectPtr Http2Session::PopSettings() { return settings; } -Http2Session::Http2Settings* Http2Session::AddSettings( - BaseObjectPtr settings) { +bool Http2Session::AddSettings(Local callback) { + Local obj; + if (!env()->http2settings_constructor_template() + ->NewInstance(env()->context()) + .ToLocal(&obj)) { + return false; + } + + BaseObjectPtr settings = + MakeDetachedBaseObject(this, obj, callback, 0); + if (!settings) + return false; + if (outstanding_settings_.size() == max_outstanding_settings_) { settings->Done(false); - return nullptr; + return false; } - Http2Settings* ptr = settings.get(); - outstanding_settings_.emplace(std::move(settings)); + IncrementCurrentSessionMemory(sizeof(*settings)); - return ptr; + settings->Send(); + outstanding_settings_.emplace(std::move(settings)); + return true; } -Http2Session::Http2Ping::Http2Ping(Http2Session* session, Local obj) +Http2Ping::Http2Ping( + Http2Session* session, + Local obj, + Local callback) : AsyncWrap(session->env(), obj, AsyncWrap::PROVIDER_HTTP2PING), session_(session), startTime_(uv_hrtime()) { + callback_.Reset(env()->isolate(), callback); +} + +void Http2Ping::MemoryInfo(MemoryTracker* tracker) const { + tracker->TrackField("callback", callback_); +} + +Local Http2Ping::callback() const { + return callback_.Get(env()->isolate()); } -void Http2Session::Http2Ping::Send(const uint8_t* payload) { - CHECK_NOT_NULL(session_); +void Http2Ping::Send(const uint8_t* payload) { + CHECK(session_); uint8_t data[8]; if (payload == nullptr) { memcpy(&data, &startTime_, arraysize(data)); payload = data; } - Http2Scope h2scope(session_); - CHECK_EQ(nghttp2_submit_ping(**session_, NGHTTP2_FLAG_NONE, payload), 0); + Http2Scope h2scope(session_.get()); + CHECK_EQ(nghttp2_submit_ping( + session_->session(), + NGHTTP2_FLAG_NONE, + payload), 0); } -void Http2Session::Http2Ping::Done(bool ack, const uint8_t* payload) { +void Http2Ping::Done(bool ack, const uint8_t* payload) { uint64_t duration_ns = uv_hrtime() - startTime_; double duration_ms = duration_ns / 1e6; - if (session_ != nullptr) session_->statistics_.ping_rtt = duration_ns; + if (session_) session_->statistics_.ping_rtt = duration_ns; - HandleScope handle_scope(env()->isolate()); + Isolate* isolate = env()->isolate(); + HandleScope handle_scope(isolate); Context::Scope context_scope(env()->context()); - Local buf = Undefined(env()->isolate()); + Local buf = Undefined(isolate); if (payload != nullptr) { - buf = Buffer::Copy(env()->isolate(), + buf = Buffer::Copy(isolate, reinterpret_cast(payload), 8).ToLocalChecked(); } Local argv[] = { - Boolean::New(env()->isolate(), ack), - Number::New(env()->isolate(), duration_ms), + ack ? v8::True(isolate) : v8::False(isolate), + Number::New(isolate, duration_ms), buf }; - MakeCallback(env()->ondone_string(), arraysize(argv), argv); + MakeCallback(callback(), arraysize(argv), argv); } -void Http2Session::Http2Ping::DetachFromSession() { - session_ = nullptr; +void Http2Ping::DetachFromSession() { + session_.reset(); } void NgHttp2StreamWrite::MemoryInfo(MemoryTracker* tracker) const { @@ -2970,6 +2992,9 @@ void Initialize(Local target, // Method to fetch the nghttp2 string description of an nghttp2 error code env->SetMethod(target, "nghttp2ErrorString", HttpErrorString); + env->SetMethod(target, "refreshDefaultSettings", RefreshDefaultSettings); + env->SetMethod(target, "packSettings", PackSettings); + env->SetMethod(target, "setCallbackFunctions", SetCallbackFunctions); Local http2SessionClassName = FIXED_ONE_BYTE_STRING(isolate, "Http2Session"); @@ -2978,7 +3003,7 @@ void Initialize(Local target, ping->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "Http2Ping")); ping->Inherit(AsyncWrap::GetConstructorTemplate(env)); Local pingt = ping->InstanceTemplate(); - pingt->SetInternalFieldCount(Http2Session::Http2Ping::kInternalFieldCount); + pingt->SetInternalFieldCount(Http2Ping::kInternalFieldCount); env->set_http2ping_constructor_template(pingt); Local setting = FunctionTemplate::New(env->isolate()); @@ -3038,113 +3063,52 @@ void Initialize(Local target, session->GetFunction(env->context()).ToLocalChecked()).Check(); Local constants = Object::New(isolate); - Local name_for_error_code = Array::New(isolate); - -#define NODE_NGHTTP2_ERROR_CODES(V) \ - V(NGHTTP2_SESSION_SERVER); \ - V(NGHTTP2_SESSION_CLIENT); \ - V(NGHTTP2_STREAM_STATE_IDLE); \ - V(NGHTTP2_STREAM_STATE_OPEN); \ - V(NGHTTP2_STREAM_STATE_RESERVED_LOCAL); \ - V(NGHTTP2_STREAM_STATE_RESERVED_REMOTE); \ - V(NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL); \ - V(NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE); \ - V(NGHTTP2_STREAM_STATE_CLOSED); \ - V(NGHTTP2_NO_ERROR); \ - V(NGHTTP2_PROTOCOL_ERROR); \ - V(NGHTTP2_INTERNAL_ERROR); \ - V(NGHTTP2_FLOW_CONTROL_ERROR); \ - V(NGHTTP2_SETTINGS_TIMEOUT); \ - V(NGHTTP2_STREAM_CLOSED); \ - V(NGHTTP2_FRAME_SIZE_ERROR); \ - V(NGHTTP2_REFUSED_STREAM); \ - V(NGHTTP2_CANCEL); \ - V(NGHTTP2_COMPRESSION_ERROR); \ - V(NGHTTP2_CONNECT_ERROR); \ - V(NGHTTP2_ENHANCE_YOUR_CALM); \ - V(NGHTTP2_INADEQUATE_SECURITY); \ - V(NGHTTP2_HTTP_1_1_REQUIRED); \ - -#define V(name) \ - NODE_DEFINE_CONSTANT(constants, name); \ - name_for_error_code->Set(env->context(), \ - static_cast(name), \ - FIXED_ONE_BYTE_STRING(isolate, \ - #name)).Check(); - NODE_NGHTTP2_ERROR_CODES(V) + + // This does alocate one more slot than needed but it's not used. +#define V(name) FIXED_ONE_BYTE_STRING(isolate, #name), + Local error_code_names[] = { + HTTP2_ERROR_CODES(V) + }; #undef V - NODE_DEFINE_HIDDEN_CONSTANT(constants, NGHTTP2_HCAT_REQUEST); - NODE_DEFINE_HIDDEN_CONSTANT(constants, NGHTTP2_HCAT_RESPONSE); - NODE_DEFINE_HIDDEN_CONSTANT(constants, NGHTTP2_HCAT_PUSH_RESPONSE); - NODE_DEFINE_HIDDEN_CONSTANT(constants, NGHTTP2_HCAT_HEADERS); - NODE_DEFINE_HIDDEN_CONSTANT(constants, NGHTTP2_NV_FLAG_NONE); - NODE_DEFINE_HIDDEN_CONSTANT(constants, NGHTTP2_NV_FLAG_NO_INDEX); - NODE_DEFINE_HIDDEN_CONSTANT(constants, NGHTTP2_ERR_DEFERRED); - NODE_DEFINE_HIDDEN_CONSTANT(constants, NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE); - NODE_DEFINE_HIDDEN_CONSTANT(constants, NGHTTP2_ERR_INVALID_ARGUMENT); - NODE_DEFINE_HIDDEN_CONSTANT(constants, NGHTTP2_ERR_STREAM_CLOSED); - NODE_DEFINE_CONSTANT(constants, NGHTTP2_ERR_FRAME_SIZE_ERROR); - - NODE_DEFINE_HIDDEN_CONSTANT(constants, STREAM_OPTION_EMPTY_PAYLOAD); - NODE_DEFINE_HIDDEN_CONSTANT(constants, STREAM_OPTION_GET_TRAILERS); - - NODE_DEFINE_CONSTANT(constants, NGHTTP2_FLAG_NONE); - NODE_DEFINE_CONSTANT(constants, NGHTTP2_FLAG_END_STREAM); - NODE_DEFINE_CONSTANT(constants, NGHTTP2_FLAG_END_HEADERS); - NODE_DEFINE_CONSTANT(constants, NGHTTP2_FLAG_ACK); - NODE_DEFINE_CONSTANT(constants, NGHTTP2_FLAG_PADDED); - NODE_DEFINE_CONSTANT(constants, NGHTTP2_FLAG_PRIORITY); - - NODE_DEFINE_CONSTANT(constants, DEFAULT_SETTINGS_HEADER_TABLE_SIZE); - NODE_DEFINE_CONSTANT(constants, DEFAULT_SETTINGS_ENABLE_PUSH); - NODE_DEFINE_CONSTANT(constants, DEFAULT_SETTINGS_MAX_CONCURRENT_STREAMS); - NODE_DEFINE_CONSTANT(constants, DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE); - NODE_DEFINE_CONSTANT(constants, DEFAULT_SETTINGS_MAX_FRAME_SIZE); - NODE_DEFINE_CONSTANT(constants, DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE); - NODE_DEFINE_CONSTANT(constants, DEFAULT_SETTINGS_ENABLE_CONNECT_PROTOCOL); - NODE_DEFINE_CONSTANT(constants, MAX_MAX_FRAME_SIZE); - NODE_DEFINE_CONSTANT(constants, MIN_MAX_FRAME_SIZE); - NODE_DEFINE_CONSTANT(constants, MAX_INITIAL_WINDOW_SIZE); - NODE_DEFINE_CONSTANT(constants, NGHTTP2_DEFAULT_WEIGHT); + Local name_for_error_code = + Array::New( + isolate, + error_code_names, + arraysize(error_code_names)); + + target->Set(context, + FIXED_ONE_BYTE_STRING(isolate, "nameForErrorCode"), + name_for_error_code).Check(); - NODE_DEFINE_CONSTANT(constants, NGHTTP2_SETTINGS_HEADER_TABLE_SIZE); - NODE_DEFINE_CONSTANT(constants, NGHTTP2_SETTINGS_ENABLE_PUSH); - NODE_DEFINE_CONSTANT(constants, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS); - NODE_DEFINE_CONSTANT(constants, NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE); - NODE_DEFINE_CONSTANT(constants, NGHTTP2_SETTINGS_MAX_FRAME_SIZE); - NODE_DEFINE_CONSTANT(constants, NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE); - NODE_DEFINE_CONSTANT(constants, NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL); +#define V(constant) NODE_DEFINE_HIDDEN_CONSTANT(constants, constant); + HTTP2_HIDDEN_CONSTANTS(V) +#undef V - NODE_DEFINE_CONSTANT(constants, PADDING_STRATEGY_NONE); - NODE_DEFINE_CONSTANT(constants, PADDING_STRATEGY_ALIGNED); - NODE_DEFINE_CONSTANT(constants, PADDING_STRATEGY_MAX); - NODE_DEFINE_CONSTANT(constants, PADDING_STRATEGY_CALLBACK); +#define V(constant) NODE_DEFINE_CONSTANT(constants, constant); + HTTP2_CONSTANTS(V) +#undef V -#define STRING_CONSTANT(NAME, VALUE) \ + // NGHTTP2_DEFAULT_WEIGHT is a macro and not a regular define + // it won't be set properly on the constants object if included + // in the HTTP2_CONSTANTS macro. + NODE_DEFINE_CONSTANT(constants, NGHTTP2_DEFAULT_WEIGHT); + +#define V(NAME, VALUE) \ NODE_DEFINE_STRING_CONSTANT(constants, "HTTP2_HEADER_" # NAME, VALUE); -HTTP_KNOWN_HEADERS(STRING_CONSTANT) -#undef STRING_CONSTANT + HTTP_KNOWN_HEADERS(V) +#undef V -#define STRING_CONSTANT(NAME, VALUE) \ +#define V(NAME, VALUE) \ NODE_DEFINE_STRING_CONSTANT(constants, "HTTP2_METHOD_" # NAME, VALUE); -HTTP_KNOWN_METHODS(STRING_CONSTANT) -#undef STRING_CONSTANT + HTTP_KNOWN_METHODS(V) +#undef V #define V(name, _) NODE_DEFINE_CONSTANT(constants, HTTP_STATUS_##name); -HTTP_STATUS_CODES(V) + HTTP_STATUS_CODES(V) #undef V - env->SetMethod(target, "refreshDefaultSettings", RefreshDefaultSettings); - env->SetMethod(target, "packSettings", PackSettings); - env->SetMethod(target, "setCallbackFunctions", SetCallbackFunctions); - - target->Set(context, - env->constants_string(), - constants).Check(); - target->Set(context, - FIXED_ONE_BYTE_STRING(isolate, "nameForErrorCode"), - name_for_error_code).Check(); + target->Set(context, env->constants_string(), constants).Check(); } } // namespace http2 } // namespace node diff --git a/src/node_http2.h b/src/node_http2.h index 1e5f99acfacec9..6b11535f84e121 100644 --- a/src/node_http2.h +++ b/src/node_http2.h @@ -21,6 +21,10 @@ namespace node { namespace http2 { +// Constants in all caps are exported as user-facing constants +// in JavaScript. Constants using the kName pattern are internal +// only. + // We strictly limit the number of outstanding unacknowledged PINGS a user // may send in order to prevent abuse. The current default cap is 10. The // user may set a different limit using a per Http2Session configuration @@ -34,16 +38,62 @@ constexpr size_t kDefaultMaxSettings = 10; constexpr uint64_t kDefaultMaxSessionMemory = 10000000; // These are the standard HTTP/2 defaults as specified by the RFC -#define DEFAULT_SETTINGS_HEADER_TABLE_SIZE 4096 -#define DEFAULT_SETTINGS_ENABLE_PUSH 1 -#define DEFAULT_SETTINGS_MAX_CONCURRENT_STREAMS 0xffffffffu -#define DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE 65535 -#define DEFAULT_SETTINGS_MAX_FRAME_SIZE 16384 -#define DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE 65535 -#define DEFAULT_SETTINGS_ENABLE_CONNECT_PROTOCOL 0 -#define MAX_MAX_FRAME_SIZE 16777215 -#define MIN_MAX_FRAME_SIZE DEFAULT_SETTINGS_MAX_FRAME_SIZE -#define MAX_INITIAL_WINDOW_SIZE 2147483647 +constexpr uint32_t DEFAULT_SETTINGS_HEADER_TABLE_SIZE = 4096; +constexpr uint32_t DEFAULT_SETTINGS_ENABLE_PUSH = 1; +constexpr uint32_t DEFAULT_SETTINGS_MAX_CONCURRENT_STREAMS = 0xffffffffu; +constexpr uint32_t DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE = 65535; +constexpr uint32_t DEFAULT_SETTINGS_MAX_FRAME_SIZE = 16384; +constexpr uint32_t DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE = 65535; +constexpr uint32_t DEFAULT_SETTINGS_ENABLE_CONNECT_PROTOCOL = 0; +constexpr uint32_t MAX_MAX_FRAME_SIZE = 16777215; +constexpr uint32_t MIN_MAX_FRAME_SIZE = DEFAULT_SETTINGS_MAX_FRAME_SIZE; +constexpr uint32_t MAX_INITIAL_WINDOW_SIZE = 2147483647; + +// Stream is not going to have any DATA frames +constexpr int STREAM_OPTION_EMPTY_PAYLOAD = 0x1; + +// Stream might have trailing headers +constexpr int STREAM_OPTION_GET_TRAILERS = 0x2; + +// Http2Stream internal states +constexpr int kStreamStateNone = 0x0; +constexpr int kStreamStateShut = 0x1; +constexpr int kStreamStateReadStart = 0x2; +constexpr int kStreamStateReadPaused = 0x4; +constexpr int kStreamStateClosed = 0x8; +constexpr int kStreamStateDestroyed = 0x10; +constexpr int kStreamStateTrailers = 0x20; + +// Http2Session internal states +constexpr int kSessionStateNone = 0x0; +constexpr int kSessionStateHasScope = 0x1; +constexpr int kSessionStateWriteScheduled = 0x2; +constexpr int kSessionStateClosed = 0x4; +constexpr int kSessionStateClosing = 0x8; +constexpr int kSessionStateSending = 0x10; +constexpr int kSessionStateWriteInProgress = 0x20; +constexpr int kSessionStateReadingStopped = 0x40; +constexpr int kSessionStateReceivePaused = 0x80; + +// The Padding Strategy determines the method by which extra padding is +// selected for HEADERS and DATA frames. These are configurable via the +// options passed in to a Http2Session object. +enum PaddingStrategy { + // No padding strategy. This is the default. + PADDING_STRATEGY_NONE, + // Attempts to ensure that the frame is 8-byte aligned + PADDING_STRATEGY_ALIGNED, + // Padding will ensure all data frames are maxFrameSize + PADDING_STRATEGY_MAX, + // Removed and turned into an alias because it is unreasonably expensive for + // very little benefit. + PADDING_STRATEGY_CALLBACK = PADDING_STRATEGY_ALIGNED +}; + +enum SessionType { + NGHTTP2_SESSION_SERVER, + NGHTTP2_SESSION_CLIENT +}; template struct Nghttp2Deleter { @@ -93,37 +143,6 @@ struct Http2RcBufferPointerTraits { using Http2Headers = NgHeaders; using Http2RcBufferPointer = NgRcBufPointer; - -enum nghttp2_session_type { - NGHTTP2_SESSION_SERVER, - NGHTTP2_SESSION_CLIENT -}; - -enum nghttp2_stream_flags { - NGHTTP2_STREAM_FLAG_NONE = 0x0, - // Writable side has ended - NGHTTP2_STREAM_FLAG_SHUT = 0x1, - // Reading has started - NGHTTP2_STREAM_FLAG_READ_START = 0x2, - // Reading is paused - NGHTTP2_STREAM_FLAG_READ_PAUSED = 0x4, - // Stream is closed - NGHTTP2_STREAM_FLAG_CLOSED = 0x8, - // Stream is destroyed - NGHTTP2_STREAM_FLAG_DESTROYED = 0x10, - // Stream has trailers - NGHTTP2_STREAM_FLAG_TRAILERS = 0x20, - // Stream has received all the data it can - NGHTTP2_STREAM_FLAG_EOS = 0x40 -}; - -enum nghttp2_stream_options { - // Stream is not going to have any DATA frames - STREAM_OPTION_EMPTY_PAYLOAD = 0x1, - // Stream might have trailing headers - STREAM_OPTION_GET_TRAILERS = 0x2, -}; - struct NgHttp2StreamWrite : public MemoryRetainer { WriteWrap* req_wrap = nullptr; uv_buf_t buf; @@ -137,38 +156,14 @@ struct NgHttp2StreamWrite : public MemoryRetainer { SET_SELF_SIZE(NgHttp2StreamWrite) }; -// The Padding Strategy determines the method by which extra padding is -// selected for HEADERS and DATA frames. These are configurable via the -// options passed in to a Http2Session object. -enum padding_strategy_type { - // No padding strategy. This is the default. - PADDING_STRATEGY_NONE, - // Attempts to ensure that the frame is 8-byte aligned - PADDING_STRATEGY_ALIGNED, - // Padding will ensure all data frames are maxFrameSize - PADDING_STRATEGY_MAX, - // Removed and turned into an alias because it is unreasonably expensive for - // very little benefit. - PADDING_STRATEGY_CALLBACK = PADDING_STRATEGY_ALIGNED -}; - -enum session_state_flags { - SESSION_STATE_NONE = 0x0, - SESSION_STATE_HAS_SCOPE = 0x1, - SESSION_STATE_WRITE_SCHEDULED = 0x2, - SESSION_STATE_CLOSED = 0x4, - SESSION_STATE_CLOSING = 0x8, - SESSION_STATE_SENDING = 0x10, - SESSION_STATE_WRITE_IN_PROGRESS = 0x20, - SESSION_STATE_READING_STOPPED = 0x40, - SESSION_STATE_NGHTTP2_RECV_PAUSED = 0x80 -}; - typedef uint32_t(*get_setting)(nghttp2_session* session, nghttp2_settings_id id); +class Http2Ping; class Http2Session; +class Http2Settings; class Http2Stream; +class Origins; // This scope should be present when any call into nghttp2 that may schedule // data to be written to the underlying transport is made, and schedules @@ -180,8 +175,7 @@ class Http2Scope { ~Http2Scope(); private: - Http2Session* session_ = nullptr; - v8::Local session_handle_; + BaseObjectPtr session_; }; // The Http2Options class is used to parse the options object passed in to @@ -191,7 +185,7 @@ class Http2Scope { class Http2Options { public: Http2Options(Http2State* http2_state, - nghttp2_session_type type); + SessionType type); ~Http2Options() = default; @@ -199,43 +193,43 @@ class Http2Options { return options_.get(); } - void SetMaxHeaderPairs(uint32_t max) { + void set_max_header_pairs(uint32_t max) { max_header_pairs_ = max; } - uint32_t GetMaxHeaderPairs() const { + uint32_t max_header_pairs() const { return max_header_pairs_; } - void SetPaddingStrategy(padding_strategy_type val) { + void set_padding_strategy(PaddingStrategy val) { padding_strategy_ = val; } - padding_strategy_type GetPaddingStrategy() const { + PaddingStrategy padding_strategy() const { return padding_strategy_; } - void SetMaxOutstandingPings(size_t max) { + void set_max_outstanding_pings(size_t max) { max_outstanding_pings_ = max; } - size_t GetMaxOutstandingPings() const { + size_t max_outstanding_pings() const { return max_outstanding_pings_; } - void SetMaxOutstandingSettings(size_t max) { + void set_max_outstanding_settings(size_t max) { max_outstanding_settings_ = max; } - size_t GetMaxOutstandingSettings() const { + size_t max_outstanding_settings() const { return max_outstanding_settings_; } - void SetMaxSessionMemory(uint64_t max) { + void set_max_session_memory(uint64_t max) { max_session_memory_ = max; } - uint64_t GetMaxSessionMemory() const { + uint64_t max_session_memory() const { return max_session_memory_; } @@ -243,7 +237,7 @@ class Http2Options { Nghttp2OptionPointer options_; uint64_t max_session_memory_ = kDefaultMaxSessionMemory; uint32_t max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS; - padding_strategy_type padding_strategy_ = PADDING_STRATEGY_NONE; + PaddingStrategy padding_strategy_ = PADDING_STRATEGY_NONE; size_t max_outstanding_pings_ = kDefaultMaxPings; size_t max_outstanding_settings_ = kDefaultMaxSettings; }; @@ -282,13 +276,13 @@ class Http2Stream : public AsyncWrap, int options = 0); ~Http2Stream() override; - nghttp2_stream* operator*(); + nghttp2_stream* operator*() const; + + nghttp2_stream* stream() const; Http2Session* session() { return session_.get(); } const Http2Session* session() const { return session_.get(); } - void EmitStatistics(); - // Required for StreamBase int ReadStart() override; @@ -312,7 +306,7 @@ class Http2Stream : public AsyncWrap, void OnTrailers(); // Submit a PRIORITY frame for this stream - int SubmitPriority(nghttp2_priority_spec* prispec, bool silent = false); + int SubmitPriority(const Http2Priority& priority, bool silent = false); // Submits an RST_STREAM frame using the given code void SubmitRstStream(const uint32_t code); @@ -331,42 +325,74 @@ class Http2Stream : public AsyncWrap, // Destroy this stream instance and free all held memory. void Destroy(); - inline bool IsDestroyed() const { - return flags_ & NGHTTP2_STREAM_FLAG_DESTROYED; + bool is_destroyed() const { + return flags_ & kStreamStateDestroyed; + } + + bool is_writable() const { + return !(flags_ & kStreamStateShut); + } + + bool is_paused() const { + return flags_ & kStreamStateReadPaused; + } + + bool is_closed() const { + return flags_ & kStreamStateClosed; + } + + bool has_trailers() const { + return flags_ & kStreamStateTrailers; + } + + void set_has_trailers(bool on = true) { + if (on) + flags_ |= kStreamStateTrailers; + else + flags_ &= ~kStreamStateTrailers; } - inline bool IsWritable() const { - return !(flags_ & NGHTTP2_STREAM_FLAG_SHUT); + void set_closed() { + flags_ |= kStreamStateClosed; } - inline bool IsPaused() const { - return flags_ & NGHTTP2_STREAM_FLAG_READ_PAUSED; + void set_destroyed() { + flags_ |= kStreamStateDestroyed; } - inline bool IsClosed() const { - return flags_ & NGHTTP2_STREAM_FLAG_CLOSED; + void set_not_writable() { + flags_ |= kStreamStateShut; } - inline bool HasTrailers() const { - return flags_ & NGHTTP2_STREAM_FLAG_TRAILERS; + void set_reading(bool on = true) { + if (on) { + flags_ |= kStreamStateReadStart; + set_paused(false); + } else {} + } + + void set_paused(bool on = true) { + if (on) + flags_ |= kStreamStateReadPaused; + else + flags_ &= ~kStreamStateReadPaused; } // Returns true if this stream is in the reading state, which occurs when - // the NGHTTP2_STREAM_FLAG_READ_START flag has been set and the - // NGHTTP2_STREAM_FLAG_READ_PAUSED flag is *not* set. - inline bool IsReading() const { - return flags_ & NGHTTP2_STREAM_FLAG_READ_START && - !(flags_ & NGHTTP2_STREAM_FLAG_READ_PAUSED); + // the kStreamStateReadStart flag has been set and the + // kStreamStateReadPaused flag is *not* set. + bool is_reading() const { + return flags_ & kStreamStateReadStart && !is_paused(); } // Returns the RST_STREAM code used to close this stream - inline int32_t code() const { return code_; } + int32_t code() const { return code_; } // Returns the stream identifier for this stream - inline int32_t id() const { return id_; } + int32_t id() const { return id_; } - inline void IncrementAvailableOutboundLength(size_t amount); - inline void DecrementAvailableOutboundLength(size_t amount); + void IncrementAvailableOutboundLength(size_t amount); + void DecrementAvailableOutboundLength(size_t amount); bool AddHeader(nghttp2_rcbuf* name, nghttp2_rcbuf* value, uint8_t flags); @@ -382,7 +408,7 @@ class Http2Stream : public AsyncWrap, return current_headers_.size(); } - inline nghttp2_headers_category headers_category() const { + nghttp2_headers_category headers_category() const { return current_headers_category_; } @@ -403,11 +429,7 @@ class Http2Stream : public AsyncWrap, int DoWrite(WriteWrap* w, uv_buf_t* bufs, size_t count, uv_stream_t* send_handle) override; - void MemoryInfo(MemoryTracker* tracker) const override { - tracker->TrackField("current_headers", current_headers_); - tracker->TrackField("queue", queue_); - } - + void MemoryInfo(MemoryTracker* tracker) const override; SET_MEMORY_INFO_NAME(Http2Stream) SET_SELF_SIZE(Http2Stream) @@ -445,10 +467,12 @@ class Http2Stream : public AsyncWrap, nghttp2_headers_category category, int options); + void EmitStatistics(); + BaseObjectWeakPtr session_; // The Parent HTTP/2 Session int32_t id_ = 0; // The Stream Identifier int32_t code_ = NGHTTP2_NO_ERROR; // The RST_STREAM code (if any) - int flags_ = NGHTTP2_STREAM_FLAG_NONE; // Internal state flags + int flags_ = kStreamStateNone; // Internal state flags uint32_t max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS; uint32_t max_header_length_ = DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE; @@ -545,29 +569,28 @@ class Http2Session : public AsyncWrap, public: Http2Session(Http2State* http2_state, v8::Local wrap, - nghttp2_session_type type = NGHTTP2_SESSION_SERVER); + SessionType type = NGHTTP2_SESSION_SERVER); ~Http2Session() override; - class Http2Ping; - class Http2Settings; - - void EmitStatistics(); - - inline StreamBase* underlying_stream() { + StreamBase* underlying_stream() { return static_cast(stream_); } void Close(uint32_t code = NGHTTP2_NO_ERROR, bool socket_closed = false); + void Consume(v8::Local stream); + void Goaway(uint32_t code, int32_t lastStreamID, const uint8_t* data, size_t len); + void AltSvc(int32_t id, uint8_t* origin, size_t origin_len, uint8_t* value, size_t value_len); - void Origin(nghttp2_origin_entry* ov, size_t count); + + void Origin(const Origins& origins); uint8_t SendPendingData(); @@ -575,25 +598,48 @@ class Http2Session : public AsyncWrap, // will be a pointer to the Http2Stream instance assigned. // This only works if the session is a client session. Http2Stream* SubmitRequest( - nghttp2_priority_spec* prispec, + const Http2Priority& priority, const Http2Headers& headers, int32_t* ret, int options = 0); - inline nghttp2_session_type type() const { return session_type_; } + SessionType type() const { return session_type_; } - inline nghttp2_session* session() const { return session_.get(); } + nghttp2_session* session() const { return session_.get(); } - inline nghttp2_session* operator*() { return session_.get(); } + nghttp2_session* operator*() { return session_.get(); } - inline uint32_t GetMaxHeaderPairs() const { return max_header_pairs_; } + uint32_t max_header_pairs() const { return max_header_pairs_; } + + const char* TypeName() const; + + bool is_destroyed() { + return (flags_ & kSessionStateClosed) || session_ == nullptr; + } - inline const char* TypeName() const; + void set_destroyed() { + flags_ |= kSessionStateClosed; + } - inline bool IsDestroyed() { - return (flags_ & SESSION_STATE_CLOSED) || session_ == nullptr; +#define IS_FLAG(name, flag) \ + bool is_##name() const { return flags_ & flag; } \ + void set_##name(bool on = true) { \ + if (on) \ + flags_ |= flag; \ + else \ + flags_ &= ~flag; \ } + IS_FLAG(in_scope, kSessionStateHasScope) + IS_FLAG(write_scheduled, kSessionStateWriteScheduled) + IS_FLAG(closing, kSessionStateClosing) + IS_FLAG(sending, kSessionStateSending) + IS_FLAG(write_in_progress, kSessionStateWriteInProgress) + IS_FLAG(reading_stopped, kSessionStateReadingStopped) + IS_FLAG(receive_paused, kSessionStateReceivePaused) + +#undef IS_FLAG + // Schedule a write if nghttp2 indicates it wants to write to the socket. void MaybeScheduleWrite(); @@ -601,15 +647,15 @@ class Http2Session : public AsyncWrap, void MaybeStopReading(); // Returns pointer to the stream, or nullptr if stream does not exist - inline Http2Stream* FindStream(int32_t id); + BaseObjectPtr FindStream(int32_t id); - inline bool CanAddStream(); + bool CanAddStream(); // Adds a stream instance to this session - inline void AddStream(Http2Stream* stream); + void AddStream(Http2Stream* stream); // Removes a stream instance from this session - inline void RemoveStream(Http2Stream* stream); + BaseObjectPtr RemoveStream(int32_t id); // Indicates whether there currently exist outgoing buffers for this stream. bool HasWritesOnSocketForStream(Http2Stream* stream); @@ -617,32 +663,22 @@ class Http2Session : public AsyncWrap, // Write data from stream_buf_ to the session ssize_t ConsumeHTTP2Data(); - void MemoryInfo(MemoryTracker* tracker) const override { - tracker->TrackField("streams", streams_); - tracker->TrackField("outstanding_pings", outstanding_pings_); - tracker->TrackField("outstanding_settings", outstanding_settings_); - tracker->TrackField("outgoing_buffers", outgoing_buffers_); - tracker->TrackFieldWithSize("stream_buf", stream_buf_.len); - tracker->TrackFieldWithSize("outgoing_storage", outgoing_storage_.size()); - tracker->TrackFieldWithSize("pending_rst_streams", - pending_rst_streams_.size() * sizeof(int32_t)); - tracker->TrackFieldWithSize("nghttp2_memory", current_nghttp2_memory_); - } - + void MemoryInfo(MemoryTracker* tracker) const override; SET_MEMORY_INFO_NAME(Http2Session) SET_SELF_SIZE(Http2Session) std::string diagnostic_name() const override; // Schedule an RstStream for after the current write finishes. - inline void AddPendingRstStream(int32_t stream_id) { + void AddPendingRstStream(int32_t stream_id) { pending_rst_streams_.emplace_back(stream_id); } - inline bool HasPendingRstStream(int32_t stream_id) { - return pending_rst_streams_.end() != std::find(pending_rst_streams_.begin(), - pending_rst_streams_.end(), - stream_id); + bool has_pending_rststream(int32_t stream_id) { + return pending_rst_streams_.end() != + std::find(pending_rst_streams_.begin(), + pending_rst_streams_.end(), + stream_id); } // Handle reads/writes from the underlying network transport. @@ -676,14 +712,13 @@ class Http2Session : public AsyncWrap, return env()->event_loop(); } - Http2State* http2_state() { - return http2_state_.get(); - } + Http2State* http2_state() const { return http2_state_.get(); } + BaseObjectPtr PopPing(); - Http2Ping* AddPing(BaseObjectPtr ping); + bool AddPing(const uint8_t* data, v8::Local callback); BaseObjectPtr PopSettings(); - Http2Settings* AddSettings(BaseObjectPtr settings); + bool AddSettings(v8::Local callback); void IncrementCurrentSessionMemory(uint64_t amount) { current_session_memory_ += amount; @@ -700,7 +735,7 @@ class Http2Session : public AsyncWrap, // Returns the current session memory including memory allocated by nghttp2, // the current outbound storage queue, and pending writes. - uint64_t GetCurrentSessionMemory() { + uint64_t current_session_memory() const { uint64_t total = current_session_memory_ + sizeof(Http2Session); total += current_nghttp2_memory_; total += outgoing_storage_.size(); @@ -708,8 +743,8 @@ class Http2Session : public AsyncWrap, } // Return true if current_session_memory + amount is less than the max - bool IsAvailableSessionMemory(uint64_t amount) { - return GetCurrentSessionMemory() + amount <= max_session_memory_; + bool has_available_session_memory(uint64_t amount) const { + return current_session_memory() + amount <= max_session_memory_; } struct Statistics { @@ -728,6 +763,8 @@ class Http2Session : public AsyncWrap, Statistics statistics_ = {}; private: + void EmitStatistics(); + // Frame Padding Strategies ssize_t OnDWordAlignedPadding(size_t frameLength, size_t maxPayloadLen); @@ -812,7 +849,7 @@ class Http2Session : public AsyncWrap, void* user_data); struct Callbacks { - inline explicit Callbacks(bool kHasGetPaddingCallback); + explicit Callbacks(bool kHasGetPaddingCallback); Nghttp2SessionCallbacksPointer callbacks; }; @@ -827,7 +864,7 @@ class Http2Session : public AsyncWrap, AliasedStruct js_fields_; // The session type: client or server - nghttp2_session_type session_type_; + SessionType session_type_; // The maximum number of header pairs permitted for streams on this session uint32_t max_header_pairs_ = DEFAULT_MAX_HEADER_LIST_PAIRS; @@ -839,12 +876,12 @@ class Http2Session : public AsyncWrap, uint64_t current_nghttp2_memory_ = 0; // The collection of active Http2Streams associated with this session - std::unordered_map streams_; + std::unordered_map> streams_; - int flags_ = SESSION_STATE_NONE; + int flags_ = kSessionStateNone; // The StreamBase instance being used for i/o - padding_strategy_type padding_strategy_ = PADDING_STRATEGY_NONE; + PaddingStrategy padding_strategy_ = PADDING_STRATEGY_NONE; // use this to allow timeout tracking during long-lasting writes uint32_t chunks_sent_since_last_write_ = 0; @@ -890,7 +927,7 @@ class Http2SessionPerformanceEntry : public performance::PerformanceEntry { Http2SessionPerformanceEntry( Http2State* http2_state, const Http2Session::Statistics& stats, - nghttp2_session_type type) : + SessionType type) : performance::PerformanceEntry( http2_state->env(), "Http2Session", "http2", stats.start_time, @@ -914,7 +951,7 @@ class Http2SessionPerformanceEntry : public performance::PerformanceEntry { int32_t stream_count() const { return stream_count_; } size_t max_concurrent_streams() const { return max_concurrent_streams_; } double stream_average_duration() const { return stream_average_duration_; } - nghttp2_session_type type() const { return session_type_; } + SessionType type() const { return session_type_; } Http2State* http2_state() const { return http2_state_.get(); } void Notify(v8::Local obj) { @@ -930,7 +967,7 @@ class Http2SessionPerformanceEntry : public performance::PerformanceEntry { int32_t stream_count_; size_t max_concurrent_streams_; double stream_average_duration_; - nghttp2_session_type session_type_; + SessionType session_type_; BaseObjectPtr http2_state_; }; @@ -975,14 +1012,14 @@ class Http2StreamPerformanceEntry BaseObjectPtr http2_state_; }; -class Http2Session::Http2Ping : public AsyncWrap { +class Http2Ping : public AsyncWrap { public: - explicit Http2Ping(Http2Session* session, v8::Local obj); - - void MemoryInfo(MemoryTracker* tracker) const override { - tracker->TrackField("session", session_); - } + explicit Http2Ping( + Http2Session* session, + v8::Local obj, + v8::Local callback); + void MemoryInfo(MemoryTracker* tracker) const override; SET_MEMORY_INFO_NAME(Http2Ping) SET_SELF_SIZE(Http2Ping) @@ -990,34 +1027,38 @@ class Http2Session::Http2Ping : public AsyncWrap { void Done(bool ack, const uint8_t* payload = nullptr); void DetachFromSession(); + v8::Local callback() const; + private: - Http2Session* session_; + BaseObjectWeakPtr session_; + v8::Global callback_; uint64_t startTime_; }; // The Http2Settings class is used to parse the settings passed in for // an Http2Session, converting those into an array of nghttp2_settings_entry // structs. -class Http2Session::Http2Settings : public AsyncWrap { +class Http2Settings : public AsyncWrap { public: - Http2Settings(Http2State* http2_state, - Http2Session* session, + Http2Settings(Http2Session* session, v8::Local obj, + v8::Local callback, uint64_t start_time = uv_hrtime()); - void MemoryInfo(MemoryTracker* tracker) const override { - tracker->TrackField("session", session_); - } - + void MemoryInfo(MemoryTracker* tracker) const override; SET_MEMORY_INFO_NAME(Http2Settings) SET_SELF_SIZE(Http2Settings) void Send(); void Done(bool ack); + v8::Local callback() const; + // Returns a Buffer instance with the serialized SETTINGS payload v8::Local Pack(); + static v8::Local Pack(Http2State* state); + // Resets the default values in the settings buffer static void RefreshDefaults(Http2State* http2_state); @@ -1026,8 +1067,17 @@ class Http2Session::Http2Settings : public AsyncWrap { get_setting fn); private: - void Init(Http2State* http2_state); - Http2Session* session_; + static size_t Init( + Http2State* http2_state, + nghttp2_settings_entry* entries); + + static v8::Local Pack( + Environment* env, + size_t count, + const nghttp2_settings_entry* entries); + + BaseObjectWeakPtr session_; + v8::Global callback_; uint64_t startTime_; size_t count_ = 0; nghttp2_settings_entry entries_[IDX_SETTINGS_COUNT]; @@ -1035,14 +1085,13 @@ class Http2Session::Http2Settings : public AsyncWrap { class Origins { public: - Origins(v8::Isolate* isolate, - v8::Local context, + Origins(Environment* env, v8::Local origin_string, size_t origin_count); ~Origins() = default; - nghttp2_origin_entry* operator*() { - return reinterpret_cast(*buf_); + const nghttp2_origin_entry* operator*() const { + return reinterpret_cast(buf_.data()); } size_t length() const { @@ -1051,9 +1100,88 @@ class Origins { private: size_t count_; - MaybeStackBuffer buf_; + AllocatedBuffer buf_; }; +#define HTTP2_HIDDEN_CONSTANTS(V) \ + V(NGHTTP2_HCAT_REQUEST) \ + V(NGHTTP2_HCAT_RESPONSE) \ + V(NGHTTP2_HCAT_PUSH_RESPONSE) \ + V(NGHTTP2_HCAT_HEADERS) \ + V(NGHTTP2_NV_FLAG_NONE) \ + V(NGHTTP2_NV_FLAG_NO_INDEX) \ + V(NGHTTP2_ERR_DEFERRED) \ + V(NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE) \ + V(NGHTTP2_ERR_INVALID_ARGUMENT) \ + V(NGHTTP2_ERR_STREAM_CLOSED) \ + V(STREAM_OPTION_EMPTY_PAYLOAD) \ + V(STREAM_OPTION_GET_TRAILERS) + +#define HTTP2_ERROR_CODES(V) \ + V(NGHTTP2_NO_ERROR) \ + V(NGHTTP2_PROTOCOL_ERROR) \ + V(NGHTTP2_INTERNAL_ERROR) \ + V(NGHTTP2_FLOW_CONTROL_ERROR) \ + V(NGHTTP2_SETTINGS_TIMEOUT) \ + V(NGHTTP2_STREAM_CLOSED) \ + V(NGHTTP2_FRAME_SIZE_ERROR) \ + V(NGHTTP2_REFUSED_STREAM) \ + V(NGHTTP2_CANCEL) \ + V(NGHTTP2_COMPRESSION_ERROR) \ + V(NGHTTP2_CONNECT_ERROR) \ + V(NGHTTP2_ENHANCE_YOUR_CALM) \ + V(NGHTTP2_INADEQUATE_SECURITY) \ + V(NGHTTP2_HTTP_1_1_REQUIRED) \ + +#define HTTP2_CONSTANTS(V) \ + V(NGHTTP2_ERR_FRAME_SIZE_ERROR) \ + V(NGHTTP2_SESSION_SERVER) \ + V(NGHTTP2_SESSION_CLIENT) \ + V(NGHTTP2_STREAM_STATE_IDLE) \ + V(NGHTTP2_STREAM_STATE_OPEN) \ + V(NGHTTP2_STREAM_STATE_RESERVED_LOCAL) \ + V(NGHTTP2_STREAM_STATE_RESERVED_REMOTE) \ + V(NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL) \ + V(NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE) \ + V(NGHTTP2_STREAM_STATE_CLOSED) \ + V(NGHTTP2_FLAG_NONE) \ + V(NGHTTP2_FLAG_END_STREAM) \ + V(NGHTTP2_FLAG_END_HEADERS) \ + V(NGHTTP2_FLAG_ACK) \ + V(NGHTTP2_FLAG_PADDED) \ + V(NGHTTP2_FLAG_PRIORITY) \ + V(DEFAULT_SETTINGS_HEADER_TABLE_SIZE) \ + V(DEFAULT_SETTINGS_ENABLE_PUSH) \ + V(DEFAULT_SETTINGS_MAX_CONCURRENT_STREAMS) \ + V(DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE) \ + V(DEFAULT_SETTINGS_MAX_FRAME_SIZE) \ + V(DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE) \ + V(DEFAULT_SETTINGS_ENABLE_CONNECT_PROTOCOL) \ + V(MAX_MAX_FRAME_SIZE) \ + V(MIN_MAX_FRAME_SIZE) \ + V(MAX_INITIAL_WINDOW_SIZE) \ + V(NGHTTP2_SETTINGS_HEADER_TABLE_SIZE) \ + V(NGHTTP2_SETTINGS_ENABLE_PUSH) \ + V(NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS) \ + V(NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE) \ + V(NGHTTP2_SETTINGS_MAX_FRAME_SIZE) \ + V(NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE) \ + V(NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL) \ + V(PADDING_STRATEGY_NONE) \ + V(PADDING_STRATEGY_ALIGNED) \ + V(PADDING_STRATEGY_MAX) \ + V(PADDING_STRATEGY_CALLBACK) \ + HTTP2_ERROR_CODES(V) + +#define HTTP2_SETTINGS(V) \ + V(HEADER_TABLE_SIZE) \ + V(ENABLE_PUSH) \ + V(MAX_CONCURRENT_STREAMS) \ + V(INITIAL_WINDOW_SIZE) \ + V(MAX_FRAME_SIZE) \ + V(MAX_HEADER_LIST_SIZE) \ + V(ENABLE_CONNECT_PROTOCOL) \ + } // namespace http2 } // namespace node diff --git a/test/parallel/test-http2-getpackedsettings.js b/test/parallel/test-http2-getpackedsettings.js index 4aa5747a053bd1..a54ab4499e1f89 100644 --- a/test/parallel/test-http2-getpackedsettings.js +++ b/test/parallel/test-http2-getpackedsettings.js @@ -7,11 +7,11 @@ const assert = require('assert'); const http2 = require('http2'); const check = Buffer.from([0x00, 0x01, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x05, 0x00, 0x00, 0x40, 0x00, 0x00, 0x04, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x05, 0x00, 0x00, 0x40, 0x00, 0x00, 0x06, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00]); const val = http2.getPackedSettings(http2.getDefaultSettings()); assert.deepStrictEqual(val, check); @@ -83,12 +83,13 @@ http2.getPackedSettings({ enablePush: false }); { const check = Buffer.from([ 0x00, 0x01, 0x00, 0x00, 0x00, 0x64, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0xc8, - 0x00, 0x05, 0x00, 0x00, 0x4e, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x64, + 0x00, 0x05, 0x00, 0x00, 0x4e, 0x20, 0x00, 0x06, 0x00, 0x00, 0x00, 0x64, - 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x08, 0x00, 0x00, 0x00, 0x00]); + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00 + ]); const packed = http2.getPackedSettings({ headerTableSize: 100,