diff --git a/.eslintrc.yaml b/.eslintrc.yaml index da49eb8b4f7c82..4735778b7bbff8 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -43,6 +43,7 @@ rules: # Best Practices # http://eslint.org/docs/rules/#best-practices accessor-pairs: error + array-callback-return: error dot-location: [error, property] eqeqeq: [error, smart] no-fallthrough: error diff --git a/.gitignore b/.gitignore index efbdc824d29289..ed88d059971e71 100644 --- a/.gitignore +++ b/.gitignore @@ -59,6 +59,7 @@ _UpgradeReport_Files/ ipch/ *.sdf *.opensdf +*.VC.db *.VC.opendb .vs/ .vscode/ diff --git a/.mailmap b/.mailmap index fd6816a5dce7d3..f04496bf3b51ca 100644 --- a/.mailmap +++ b/.mailmap @@ -188,6 +188,8 @@ Kathy Truong k3kathy Kazuyuki Yamada Keith M Wesolowski Kelsey Breseman +Khaidi Chu XadillaX +Khaidi Chu Kiyoshi Nomo kysnm Koichi Kobayashi Kris Kowal @@ -264,6 +266,7 @@ Roman Klauke Roman Reiss Ron Korving Ron Korving ronkorving +Ruben Bridgewater Russell Dempsey Ryan Dahl Ryan Emery diff --git a/AUTHORS b/AUTHORS index 8d8e74493aff0a..57d5a25ea0a7e3 100644 --- a/AUTHORS +++ b/AUTHORS @@ -911,7 +911,7 @@ HUANG Wei DC Daniel Turing Julie Pagano -Ruben Bridgewater +Ruben Bridgewater Felix Becker Igor Klopov Tsarevich Dmitry @@ -1493,7 +1493,7 @@ Sreepurna Jasti Rafael Fragoso Andrei Cioromila Frank Lanitz -XadillaX +Khaidi Chu Akshay Iyer Rick Bullotta Rajaram Gaunker @@ -1532,7 +1532,6 @@ Dan Homola cornholio <0@mcornholio.ru> Tamás Hódi DuanPengfei <2459714173@qq.com> -Ruben Bridgewater Lakshmi Swetha Gopireddy Rob Wu Steven Winston @@ -2036,5 +2035,34 @@ Hannes Magnusson ChungNgoops Jose M. Palacios Diaz hmammedzadeh +IHsuan +Francisco Gerardo Neri Andriano +Shilo Mangam +idandagan1 +Cameron Moorehead +TomerOmri +Collins Abitekaniza +Federico Kauffman +Benno Fünfstück +Ram Goli +babygoat +Will Clark +Jem Bezooyen +Haejin Jo +Hakan Kimeiga +Tyler +Shinya Kanamaru +you12724 +routerman +April Webster +Jure Triglav +alnyan +rt33 +Ulmanb +xortiz +Waleed Ashraf +Mir Mufaqam Ali +Nicholas Drane +Shobhit Chittora # Generated by tools/update-authors.sh diff --git a/COLLABORATOR_GUIDE.md b/COLLABORATOR_GUIDE.md index 358fd59476d2cc..2569570b8d03bd 100644 --- a/COLLABORATOR_GUIDE.md +++ b/COLLABORATOR_GUIDE.md @@ -4,7 +4,7 @@ * [Issues and Pull Requests](#issues-and-pull-requests) - [Managing Issues and Pull Requests](#managing-issues-and-pull-requests) - - [Welcoming First-Time Contributiors](#welcoming-first-time-contributiors) + - [Welcoming First-Time Contributors](#welcoming-first-time-contributors) - [Closing Issues and Pull Requests](#closing-issues-and-pull-requests) * [Accepting Modifications](#accepting-modifications) - [Code Reviews and Consensus Seeking](#code-reviews-and-consensus-seeking) @@ -33,7 +33,7 @@ - [How is an LTS release cut?](#how-is-an-lts-release-cut) This document contains information for Collaborators of the Node.js -project regarding maintaining the code, documentation, and issues. +project regarding managing the project's code, documentation, and issue tracker. Collaborators should be familiar with the guidelines for new contributors in [CONTRIBUTING.md](./CONTRIBUTING.md) and also @@ -52,11 +52,11 @@ may also notify other qualified parties for more input on an issue or a pull request. [See "Who to CC in issues"](./doc/onboarding-extras.md#who-to-cc-in-issues) -### Welcoming First-Time Contributiors +### Welcoming First-Time Contributors Courtesy should always be shown to individuals submitting issues and pull requests to the Node.js project. Be welcoming to first-time contributors, -identified by the GitHub ![badge](./doc/first_timer_badge.png) badge. +identified by the GitHub ![First-time contributor](./doc/first_timer_badge.png) badge. For first-time contributors, check if the commit author is the same as the pull request author, and ask if they have configured their git @@ -116,6 +116,11 @@ oppose the PR, it can be landed. Where there is disagreement among TSC members or objections from one or more Collaborators, `semver-major` pull requests should be put on the TSC meeting agenda. +#### Helpful resources + +* How to respectfully and usefully review code, part [one](https://mtlynch.io/human-code-reviews-1/) and [two](https://mtlynch.io/human-code-reviews-2/) +* [How to write a positive code review](https://css-tricks.com/code-review-etiquette/) + ### Waiting for Approvals Before landing pull requests, sufficient time should be left for input @@ -142,6 +147,7 @@ test should *fail* before the change, and *pass* after the change. All pull requests that modify executable code should be subjected to continuous integration tests on the [project CI server](https://ci.nodejs.org/). +The pull request should have a CI status indicator if possible. #### Useful CI Jobs @@ -200,11 +206,10 @@ Node.js API are internal: - Any native C/C++ APIs/ABIs exported by the Node.js `*.h` header files that are hidden behind the `NODE_WANT_INTERNALS` flag are internal. -Exception to each of these points can be made if use or behavior of a given -internal API can be demonstrated to be sufficiently relied upon by the Node.js -ecosystem such that any changes would cause too much breakage. The threshold -for what qualifies as too much breakage is to be decided on a case-by-case -basis by the TSC. +Exceptions can be made if use or behavior of a given internal API can be +demonstrated to be sufficiently relied upon by the Node.js ecosystem such that +any changes would cause too much breakage. The threshold for what qualifies as +too much breakage is to be decided on a case-by-case basis by the TSC. If it is determined that a currently undocumented object, property, method, argument, or event *should* be documented, then a pull request adding the @@ -243,14 +248,14 @@ properties to an options argument) are semver-minor changes. #### Breaking Changes and Deprecations -With a few notable exceptions outlined below, when backwards incompatible -changes to a *Public* API are necessary, the existing API *must* be deprecated -*first* and the new API either introduced in parallel or added after the next -major Node.js version following the deprecation as a replacement for the -deprecated API. In other words, as a general rule, existing *Public* APIs -*must not* change (in a backwards incompatible way) without a deprecation. +With a few exceptions outlined below, when backward-incompatible changes to a +*Public* API are necessary, the existing API *must* be deprecated *first* and +the new API either introduced in parallel or added after the next major Node.js +version following the deprecation as a replacement for the deprecated API. In +other words, as a general rule, existing *Public* APIs *must not* change (in a +backward-incompatible way) without a deprecation. -Exception to this rule is given in the following cases: +Exceptions to this rule may be made in the following cases: * Adding or removing errors thrown or reported by a Public API; * Changing error messages; @@ -351,7 +356,7 @@ recommended but not required. ### Deprecations _Deprecation_ refers to the identification of Public APIs that should no longer -be used and that may be removed or modified in non-backwards compatible ways in +be used and that may be removed or modified in backward-incompatible ways in a future major release of Node.js. Deprecation may be used with internal APIs if there is expected impact on the user community. @@ -491,7 +496,7 @@ Check and re-review the changes: $ git diff upstream/master ``` -Check number of commits and commit messages: +Check the number of commits and commit messages: ```text $ git log upstream/master...master @@ -652,7 +657,7 @@ commit final. #### What is LTS? Long Term Support (often referred to as *LTS*) guarantees application developers -a 30 month support cycle with specific versions of Node.js. +a 30-month support cycle with specific versions of Node.js. You can find more information [in the full release plan](https://github.com/nodejs/Release#release-plan). @@ -665,7 +670,7 @@ certain performance improvements that can be demonstrated to not break existing applications. Semver-minor changes are only permitted if required for bug fixes and then only on a case-by-case basis with LTS WG and possibly Technical Steering Committee (TSC) review. Semver-major changes are permitted only if -required for security related fixes. +required for security-related fixes. Once a Current branch moves into Maintenance mode, only **critical** bugs, **critical** security fixes, and documentation updates will be permitted. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9f8f89cdaa999e..b1cc67ada553ff 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,17 +1,15 @@ # Contributing to Node.js -Contributions to Node.js may come in many forms. Some contribute code changes, -others contribute docs, others help answer questions from users, help keep the -infrastructure running, or seek out ways of advocating for Node.js users of all -types. +Contributions to Node.js include code, documentation, answering user questions, +running the project's infrastructure, and advocating for all types of Node.js +users. The Node.js project welcomes all contributions from anyone willing to work in -good faith both with other contributors and with the community. No contribution -is too small and all contributions are valued. +good faith with other contributors and the community. No contribution is too +small and all contributions are valued. -This guide details the basic steps for getting started contributing to the -Node.js project's core `nodejs/node` GitHub Repository and describes what to -expect throughout each step of the process. +This guide explains the process for contributing to the Node.js project's core +`nodejs/node` GitHub Repository and describes what to expect at each step. * [Code of Conduct](#code-of-conduct) * [Bad Actors](#bad-actors) @@ -201,9 +199,8 @@ functional guidelines of the Node.js project. ## Pull Requests -Pull Requests are the way in which concrete changes are made to the code, -documentation, dependencies, and tools contained with the `nodejs/node` -repository. +Pull Requests are the way concrete changes are made to the code, documentation, +dependencies, and tools contained in the `nodejs/node` repository. There are two fundamental components of the Pull Request process: one concrete and technical, and one more process oriented. The concrete and technical @@ -605,12 +602,11 @@ your name on it. Congratulations and thanks for your contribution! All Node.js contributors who choose to review and provide feedback on Pull Requests have a responsibility to both the project and the individual making the contribution. Reviews and feedback must be helpful, insightful, and geared -towards improving the contribution as opposed to simply blocking it or -stopping it. If there are reasons why you feel the PR should not land, explain -what those are. Do not expect to be able to block a Pull Request from advancing -simply because you say "No" without giving an explanation. It is also important -to be open to having your mind changed, and to being open to working with the -contributor to make the Pull Request better. +towards improving the contribution as opposed to simply blocking it. If there +are reasons why you feel the PR should not land, explain what those are. Do not +expect to be able to block a Pull Request from advancing simply because you say +"No" without giving an explanation. Be open to having your mind changed. Be open +to working with the contributor to make the Pull Request better. Reviews that are dismissive or disrespectful of the contributor or any other reviewers are strictly counter to the [Code of Conduct][]. diff --git a/CPP_STYLE_GUIDE.md b/CPP_STYLE_GUIDE.md index 62c96a8fd12e35..6266ee03b7c538 100644 --- a/CPP_STYLE_GUIDE.md +++ b/CPP_STYLE_GUIDE.md @@ -4,6 +4,7 @@ * [Formatting](#formatting) * [Left-leaning (C++ style) asterisks for pointer declarations](#left-leaning-c-style-asterisks-for-pointer-declarations) + * [C++ style comments](#c-style-comments) * [2 spaces of indentation for blocks or bodies of conditionals](#2-spaces-of-indentation-for-blocks-or-bodies-of-conditionals) * [4 spaces of indentation for statement continuations](#4-spaces-of-indentation-for-statement-continuations) * [Align function arguments vertically](#align-function-arguments-vertically) @@ -33,6 +34,26 @@ these rules: `char* buffer;` instead of `char *buffer;` +## C++ style comments + +Use C++ style comments (`//`) for both single-line and multi-line comments. +Comments should also start with uppercase and finish with a dot. + +Examples: + +```c++ +// A single-line comment. + +// Multi-line comments +// should also use C++ +// style comments. +``` + +The codebase may contain old C style comments (`/* */`) from before this was the +preferred style. Feel free to update old comments to the preferred style when +working on code in the immediate vicinity or when changing/improving those +comments. + ## 2 spaces of indentation for blocks or bodies of conditionals ```c++ diff --git a/Makefile b/Makefile index 992af027687657..b58a32d2c28be0 100644 --- a/Makefile +++ b/Makefile @@ -60,6 +60,7 @@ BUILD_RELEASE_FLAGS ?= $(BUILD_DOWNLOAD_FLAGS) $(BUILD_INTL_FLAGS) # or set the V environment variable to an empty string. V ?= 1 +.PHONY: all # BUILDTYPE=Debug builds both release and debug builds. If you want to compile # just the debug build, run `make -C out BUILDTYPE=Debug` instead. ifeq ($(BUILDTYPE),Release) @@ -68,6 +69,7 @@ else all: out/Makefile $(NODE_EXE) $(NODE_G_EXE) endif +.PHONY: help # To add a target to the help, add a double comment (##) on the target line. help: ## Print help for targets with comments. @printf "For more targets and info see the comments in the Makefile.\n\n" @@ -100,12 +102,15 @@ out/Makefile: common.gypi deps/uv/uv.gyp deps/http_parser/http_parser.gyp \ config.gypi: configure $(error Missing or stale $@, please run ./$<) +.PHONY: install install: all ## Installs node into $PREFIX (default=/usr/local). $(PYTHON) tools/install.py $@ '$(DESTDIR)' '$(PREFIX)' +.PHONY: uninstall uninstall: ## Uninstalls node from $PREFIX (default=/usr/local). $(PYTHON) tools/install.py $@ '$(DESTDIR)' '$(PREFIX)' +.PHONY: clean clean: ## Remove build artifacts. $(RM) -r out/Makefile $(NODE_EXE) $(NODE_G_EXE) out/$(BUILDTYPE)/$(NODE_EXE) \ out/$(BUILDTYPE)/node.exp @@ -118,6 +123,7 @@ clean: ## Remove build artifacts. $(RM) -r test/.tmp* $(MAKE) test-addons-clean +.PHONY: distclean distclean: $(RM) -r out $(RM) config.gypi icu_config.gypi config_fips.gypi @@ -129,8 +135,10 @@ distclean: $(RM) $(BINARYTAR).* $(TARBALL).* $(RM) -r deps/v8/testing/gmock +.PHONY: check check: test +.PHONY: coverage-clean # Remove files generated by running coverage, put the non-instrumented lib back # in place coverage-clean: @@ -146,13 +154,14 @@ coverage-clean: $(RM) out/$(BUILDTYPE)/obj.target/cctest/src/*.gcno $(RM) out/$(BUILDTYPE)/obj.target/cctest/test/cctest/*.gcno +.PHONY: coverage # Build and test with code coverage reporting. Leave the lib directory # instrumented for any additional runs the user may want to make. # For C++ coverage reporting, this needs to be run in conjunction with configure # --coverage. html coverage reports will be created under coverage/ - coverage: coverage-test ## Run the tests and generate a coverage report. +.PHONY: coverage-build coverage-build: all mkdir -p node_modules if [ ! -d node_modules/istanbul-merge ]; then \ @@ -171,6 +180,7 @@ coverage-build: all $(NODE) ./node_modules/.bin/nyc instrument --extension .js --extension .mjs lib_/ lib/ $(MAKE) +.PHONY: coverage-test coverage-test: coverage-build $(RM) -r out/$(BUILDTYPE)/.coverage $(RM) -r .cov_tmp @@ -198,19 +208,23 @@ coverage-test: coverage-build @grep -A3 Lines coverage/cxxcoverage.html | grep style \ | sed 's/<[^>]*>//g'| sed 's/ //g' +.PHONY: cctest cctest: all @out/$(BUILDTYPE)/$@ --gtest_filter=$(GTEST_FILTER) +.PHONY: list-gtests list-gtests: ifeq (,$(wildcard out/$(BUILDTYPE)/cctest)) $(error Please run 'make cctest' first) endif @out/$(BUILDTYPE)/cctest --gtest_list_tests +.PHONY: v8 v8: tools/make-v8.sh $(MAKE) -C deps/v8 $(V8_ARCH).$(BUILDTYPE_LOWER) $(V8_BUILD_OPTIONS) +.PHONY: test test: all ## Default test target. Runs default tests, linters, and builds docs. $(MAKE) -s build-addons $(MAKE) -s build-addons-napi @@ -218,22 +232,19 @@ test: all ## Default test target. Runs default tests, linters, and builds docs. $(MAKE) -s lint $(MAKE) -s cctest $(PYTHON) tools/test.py --mode=release -J \ - $(CI_ASYNC_HOOKS) \ $(CI_JS_SUITES) \ $(CI_NATIVE_SUITES) \ - $(CI_DOC) \ - known_issues + $(CI_DOC) +.PHONY: test-only # For a quick test, does not run linter or build doc test-only: all $(MAKE) build-addons $(MAKE) build-addons-napi $(MAKE) cctest $(PYTHON) tools/test.py --mode=release -J \ - $(CI_ASYNC_HOOKS) \ $(CI_JS_SUITES) \ - $(CI_NATIVE_SUITES) \ - known_issues + $(CI_NATIVE_SUITES) test-cov: all $(MAKE) build-addons @@ -314,6 +325,7 @@ test/addons/.buildstamp: config.gypi \ done touch $@ +.PHONY: build-addons # .buildstamp needs $(NODE_EXE) but cannot depend on it # directly because it calls make recursively. The parent make cannot know # if the subprocess touched anything so it pessimistically assumes that @@ -353,6 +365,7 @@ test/addons-napi/.buildstamp: config.gypi \ done touch $@ +.PHONY: build-addons-napi # .buildstamp needs $(NODE_EXE) but cannot depend on it # directly because it calls make recursively. The parent make cannot know # if the subprocess touched anything so it pessimistically assumes that @@ -361,6 +374,7 @@ test/addons-napi/.buildstamp: config.gypi \ # TODO(bnoordhuis) Force rebuild after gyp or node-gyp update. build-addons-napi: | $(NODE_EXE) test/addons-napi/.buildstamp +.PHONY: clear-stalled clear-stalled: # Clean up any leftover processes but don't error if found. ps awwx | grep Release/node | grep -v grep | cat @@ -369,9 +383,11 @@ clear-stalled: echo $${PS_OUT} | xargs kill; \ fi +.PHONY: test-gc test-gc: all test/gc/build/Release/binding.node $(PYTHON) tools/test.py --mode=release gc +.PHONY: test-gc-clean test-gc-clean: $(RM) -r test/gc/build @@ -379,6 +395,7 @@ test-build: | all build-addons build-addons-napi test-build-addons-napi: all build-addons-napi +.PHONY: test-all test-all: test-build test/gc/build/Release/binding.node ## Run everything in test/. $(PYTHON) tools/test.py --mode=debug,release @@ -386,10 +403,10 @@ test-all-valgrind: test-build $(PYTHON) tools/test.py --mode=debug,release --valgrind CI_NATIVE_SUITES ?= addons addons-napi -CI_ASYNC_HOOKS := async-hooks CI_JS_SUITES ?= default CI_DOC := doctool +.PHONY: test-ci-native # Build and test addons without building anything else test-ci-native: LOGLEVEL := info test-ci-native: | test/addons/.buildstamp test/addons-napi/.buildstamp @@ -397,11 +414,12 @@ test-ci-native: | test/addons/.buildstamp test/addons-napi/.buildstamp --mode=release --flaky-tests=$(FLAKY_TESTS) \ $(TEST_CI_ARGS) $(CI_NATIVE_SUITES) +.PHONY: test-ci-js # This target should not use a native compiler at all test-ci-js: | clear-stalled $(PYTHON) tools/test.py $(PARALLEL_ARGS) -p tap --logfile test.tap \ --mode=release --flaky-tests=$(FLAKY_TESTS) \ - $(TEST_CI_ARGS) $(CI_ASYNC_HOOKS) $(CI_JS_SUITES) known_issues + $(TEST_CI_ARGS) $(CI_JS_SUITES) # Clean up any leftover processes, error if found. ps awwx | grep Release/node | grep -v grep | cat @PS_OUT=`ps awwx | grep Release/node | grep -v grep | awk '{print $$1}'`; \ @@ -409,13 +427,13 @@ test-ci-js: | clear-stalled echo $${PS_OUT} | xargs kill; exit 1; \ fi +.PHONY: test-ci test-ci: LOGLEVEL := info test-ci: | clear-stalled build-addons build-addons-napi doc-only out/Release/cctest --gtest_output=tap:cctest.tap $(PYTHON) tools/test.py $(PARALLEL_ARGS) -p tap --logfile test.tap \ --mode=release --flaky-tests=$(FLAKY_TESTS) \ - $(TEST_CI_ARGS) $(CI_ASYNC_HOOKS) $(CI_JS_SUITES) $(CI_NATIVE_SUITES) \ - $(CI_DOC) known_issues + $(TEST_CI_ARGS) $(CI_JS_SUITES) $(CI_NATIVE_SUITES) $(CI_DOC) # Clean up any leftover processes, error if found. ps awwx | grep Release/node | grep -v grep | cat @PS_OUT=`ps awwx | grep Release/node | grep -v grep | awk '{print $$1}'`; \ @@ -448,9 +466,11 @@ test-node-inspect: $(NODE_EXE) test-tick-processor: all $(PYTHON) tools/test.py tick-processor +.PHONY: test-hash-seed test-hash-seed: all $(NODE) test/pummel/test-hash-seed.js +.PHONY: test-doc test-doc: doc-only $(MAKE) lint $(PYTHON) tools/test.py $(CI_DOC) @@ -464,16 +484,20 @@ test-npm: $(NODE_EXE) ## Run the npm test suite on deps/npm. test-npm-publish: $(NODE_EXE) npm_package_config_publishtest=true $(NODE) deps/npm/test/run.js +.PHONY: test-addons-napi test-addons-napi: test-build-addons-napi $(PYTHON) tools/test.py --mode=release addons-napi +.PHONY: test-addons-napi-clean test-addons-napi-clean: $(RM) -r test/addons-napi/*/build $(RM) test/addons-napi/.buildstamp +.PHONY: test-addons test-addons: test-build test-addons-napi $(PYTHON) tools/test.py --mode=release addons +.PHONY: test-addons-clean test-addons-clean: $(RM) -r test/addons/??_*/ $(RM) -r test/addons/*/build @@ -499,6 +523,10 @@ test-with-async-hooks: $(CI_NATIVE_SUITES) +.PHONY: test-v8 +.PHONY: test-v8-all +.PHONY: test-v8-benchmarks +.PHONY: test-v8-intl ifneq ("","$(wildcard deps/v8/tools/run-tests.py)") test-v8: v8 ## Runs the V8 test suite on deps/v8. # note: performs full test unless QUICKCHECK is specified @@ -545,6 +573,7 @@ apidocs_json = $(addprefix out/,$(apidoc_sources:.md=.json)) apiassets = $(subst api_assets,api/assets,$(addprefix out/,$(wildcard doc/api_assets/*))) +.PHONY: doc-only # This uses the locally built node if available, otherwise uses the global node doc-only: $(apidoc_dirs) $(apiassets) # If it's a source tarball, assets are already in doc/api/assets, @@ -554,6 +583,7 @@ doc-only: $(apidoc_dirs) $(apiassets) fi; @$(MAKE) -s $(apidocs_html) $(apidocs_json) +.PHONY: doc doc: $(NODE_EXE) doc-only out/doc: @@ -601,16 +631,20 @@ out/doc/api/%.json: doc/api/%.md out/doc/api/%.html: doc/api/%.md $(call available-node, $(gen-html)) +.PHONY: docopen docopen: $(apidocs_html) @$(PYTHON) -mwebbrowser file://$(PWD)/out/doc/api/all.html +.PHONY: docclean docclean: $(RM) -r out/doc +.PHONY: build-ci build-ci: $(PYTHON) ./configure $(CONFIG_FLAGS) $(MAKE) +.PHONY: run-ci run-ci: build-ci $(MAKE) test-ci @@ -751,6 +785,7 @@ XZ_COMPRESSION ?= 9e PKG=$(TARNAME).pkg MACOSOUTDIR=out/macos +.PHONY: release-only release-only: @if [ "$(DISTTYPE)" != "nightly" ] && [ "$(DISTTYPE)" != "next-nightly" ] && \ `grep -q REPLACEME doc/api/*.md`; then \ @@ -834,6 +869,7 @@ $(PKG): release-only --package-path $(MACOSOUTDIR)/pkgs ./$(PKG) SIGN="$(PRODUCTSIGN_CERT)" PKG="$(PKG)" bash tools/osx-productsign.sh +.PHONY: pkg pkg: $(PKG) pkg-upload: pkg @@ -866,6 +902,7 @@ ifeq ($(XZ), 0) endif $(RM) $(TARNAME).tar +.PHONY: tar tar: $(TARBALL) ## Create a source tarball. tar-upload: tar @@ -885,6 +922,7 @@ doc-upload: doc scp -pr out/doc/* $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/docs/ ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/docs.done" +.PHONY: $(TARBALL)-headers $(TARBALL)-headers: release-only $(PYTHON) ./configure \ --prefix=/ \ @@ -939,6 +977,7 @@ ifeq ($(XZ), 0) endif $(RM) $(BINARYNAME).tar +.PHONY: binary binary: $(BINARYTAR) ## Build release binary tarballs. binary-upload: binary @@ -952,27 +991,34 @@ ifeq ($(XZ), 0) ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-$(OSTYPE)-$(ARCH).tar.xz.done" endif +.PHONY: bench-net bench-net: all @$(NODE) benchmark/run.js net bench-crypto: all @$(NODE) benchmark/run.js crypto +.PHONY: bench-tls bench-tls: all @$(NODE) benchmark/run.js tls +.PHONY: bench-http bench-http: all @$(NODE) benchmark/run.js http +.PHONY: bench-fs bench-fs: all @$(NODE) benchmark/run.js fs +.PHONY: bench-misc bench-misc: benchmark/misc/function_call/build/Release/binding.node @$(NODE) benchmark/run.js misc +.PHONY: bench-array bench-array: all @$(NODE) benchmark/run.js arrays +.PHONY: bench-buffer bench-buffer: all @$(NODE) benchmark/run.js buffers @@ -988,17 +1034,22 @@ bench-util: all bench-dgram: all @$(NODE) benchmark/run.js dgram +.PHONY: bench-all bench-all: bench bench-misc bench-array bench-buffer bench-url bench-events bench-dgram bench-util +.PHONY: bench bench: bench-net bench-http bench-fs bench-tls ## Run node benchmarks. +.PHONY: bench-ci bench-ci: bench +.PHONY: lint-md-clean lint-md-clean: $(RM) -r tools/remark-cli/node_modules $(RM) -r tools/remark-preset-lint-node/node_modules $(RM) tools/.*mdlintstamp +.PHONY: lint-md-build lint-md-build: @if [ ! -d tools/remark-cli/node_modules ]; then \ echo "Markdown linter: installing remark-cli into tools/"; \ @@ -1007,6 +1058,7 @@ lint-md-build: echo "Markdown linter: installing remark-preset-lint-node into tools/"; \ cd tools/remark-preset-lint-node && ../../$(NODE) ../../$(NPM) install; fi +.PHONY: lint-md ifneq ("","$(wildcard tools/remark-cli/node_modules/)") LINT_MD_TARGETS = src lib benchmark tools/doc tools/icu LINT_MD_ROOT_DOCS := $(wildcard *.md) @@ -1038,6 +1090,7 @@ LINT_JS_CMD = tools/eslint/bin/eslint.js --cache \ --rulesdir=tools/eslint-rules --ext=.js,.mjs,.md \ $(LINT_JS_TARGETS) +.PHONY: lint-js-fix lint-js-fix: @if [ -x $(NODE) ]; then \ $(NODE) $(LINT_JS_CMD) --fix; \ @@ -1045,6 +1098,7 @@ lint-js-fix: node $(LINT_JS_CMD) --fix; \ fi +.PHONY: lint-js lint-js: @echo "Running JS linter..." @if [ -x $(NODE) ]; then \ @@ -1056,6 +1110,7 @@ lint-js: jslint: lint-js @echo "Please use lint-js instead of jslint" +.PHONY: lint-js-ci lint-js-ci: @echo "Running JS linter..." @if [ -x $(NODE) ]; then \ @@ -1100,6 +1155,7 @@ LINT_CPP_FILES = $(filter-out $(LINT_CPP_EXCLUDE), $(wildcard \ # and the actual filename is generated so it won't match header guards ADDON_DOC_LINT_FLAGS=-whitespace/ending_newline,-build/header_guard +.PHONY: lint-cpp lint-cpp: tools/.cpplintstamp tools/.cpplintstamp: $(LINT_CPP_FILES) @@ -1115,6 +1171,8 @@ lint-addon-docs: test/addons/.docbuildstamp cpplint: lint-cpp @echo "Please use lint-cpp instead of cpplint" +.PHONY: lint +.PHONY: lint-ci ifneq ("","$(wildcard tools/eslint/)") lint: ## Run JS, C++, MD and doc linters. @EXIT_STATUS=0 ; \ @@ -1141,84 +1199,7 @@ lint: lint-ci: lint endif +.PHONY: lint-clean lint-clean: $(RM) tools/.*lintstamp $(RM) .eslintcache - -.PHONY: $(TARBALL)-headers \ - all \ - bench \ - bench \ - bench-all \ - bench-array \ - bench-buffer \ - bench-ci \ - bench-fs \ - bench-http \ - bench-http-simple \ - bench-idle \ - bench-misc \ - bench-net \ - bench-tls \ - binary \ - blog \ - blogclean \ - build-addons \ - build-addons-napi \ - build-ci \ - cctest \ - check \ - clean \ - clear-stalled \ - coverage \ - coverage-build \ - coverage-clean \ - coverage-test \ - dist \ - distclean \ - doc \ - doc-only \ - docclean \ - docopen \ - dynamiclib \ - help \ - install \ - install-bin \ - install-includes \ - lint \ - lint-clean \ - lint-ci \ - lint-cpp \ - lint-js \ - lint-js-ci \ - lint-js-fix \ - list-gtests \ - lint-md \ - lint-md-build \ - lint-md-clean \ - pkg \ - release-only \ - run-ci \ - staticlib \ - tar \ - test \ - test-addons \ - test-addons-clean \ - test-addons-napi \ - test-addons-napi-clean \ - test-all \ - test-ci \ - test-ci-js \ - test-ci-native \ - test-doc \ - test-gc \ - test-gc-clean \ - test-hash-seed \ - test-only \ - test-v8 \ - test-v8-all \ - test-v8-benchmarks \ - test-v8-intl \ - uninstall \ - v8 \ - website-upload diff --git a/README.md b/README.md index db9696afb1a899..85a27f549a5150 100644 --- a/README.md +++ b/README.md @@ -169,23 +169,22 @@ officially supported platforms. ## Security -All security bugs in Node.js are taken seriously and should be reported by -emailing security@nodejs.org. This will be delivered to a subset of the project -team who handle security issues. Please don't disclose security bugs -publicly until they have been handled by the security team. +Security flaws in Node.js should be reported by emailing security@nodejs.org. +Please do not disclose security bugs publicly until they have been handled by +the security team. -Your email will be acknowledged within 24 hours, and you’ll receive a more +Your email will be acknowledged within 24 hours, and you will receive a more detailed response to your email within 48 hours indicating the next steps in handling your report. There are no hard and fast rules to determine if a bug is worth reporting as -a security issue. The general rule is any issue worth reporting -must allow an attacker to compromise the confidentiality, integrity -or availability of the Node.js application or its system for which the attacker -does not already have the capability. +a security issue. The general rule is an issue worth reporting should allow an +attacker to compromise the confidentiality, integrity, or availability of the +Node.js application or its system for which the attacker does not already have +the capability. To illustrate the point, here are some examples of past issues and what the -Security Reponse Team thinks of them. When in doubt, however, please do send +Security Response Team thinks of them. When in doubt, however, please do send us a report nonetheless. @@ -250,8 +249,6 @@ For more information about the governance of the Node.js project, see **Fedor Indutny** <fedor.indutny@gmail.com> * [jasnell](https://github.com/jasnell) - **James M Snell** <jasnell@gmail.com> (he/him) -* [joshgav](https://github.com/joshgav) - -**Josh Gavant** <josh.gavant@outlook.com> * [joyeecheung](https://github.com/joyeecheung) - **Joyee Cheung** <joyeec9h3@gmail.com> (she/her) * [mcollina](https://github.com/mcollina) - @@ -283,6 +280,8 @@ For more information about the governance of the Node.js project, see **Chris Dickinson** <christopher.s.dickinson@gmail.com> * [isaacs](https://github.com/isaacs) - **Isaac Z. Schlueter** <i@izs.me> +* [joshgav](https://github.com/joshgav) - +**Josh Gavant** <josh.gavant@outlook.com> * [nebrius](https://github.com/nebrius) - **Bryan Hughes** <bryan@nebri.us> * [orangemocha](https://github.com/orangemocha) - @@ -412,8 +411,6 @@ For more information about the governance of the Node.js project, see **Luca Maraschi** <luca.maraschi@gmail.com> (he/him) * [maclover7](https://github.com/maclover7) - **Jon Moss** <me@jonathanmoss.me> (he/him) -* [matthewloring](https://github.com/matthewloring) - -**Matthew Loring** <mattloring@google.com> * [mcollina](https://github.com/mcollina) - **Matteo Collina** <matteo.collina@gmail.com> (he/him) * [mhdawson](https://github.com/mhdawson) - @@ -476,6 +473,8 @@ For more information about the governance of the Node.js project, see **Roman Reiss** <me@silverwind.io> * [srl295](https://github.com/srl295) - **Steven R Loomis** <srloomis@us.ibm.com> +* [starkwang](https://github.com/starkwang) - +**Weijia Wang** <starkwang@126.com> * [stefanmb](https://github.com/stefanmb) - **Stefan Budeanu** <stefan@budeanu.com> * [targos](https://github.com/targos) - @@ -487,7 +486,7 @@ For more information about the governance of the Node.js project, see * [thlorenz](https://github.com/thlorenz) - **Thorsten Lorenz** <thlorenz@gmx.de> * [TimothyGu](https://github.com/TimothyGu) - -**Timothy Gu** <timothygu99@gmail.com> (he/him) +**Tiancheng "Timothy" Gu** <timothygu99@gmail.com> (he/him) * [tniessen](https://github.com/tniessen) - **Tobias Nießen** <tniessen@tnie.de> * [trevnorris](https://github.com/trevnorris) - @@ -517,6 +516,8 @@ For more information about the governance of the Node.js project, see **Isaac Z. Schlueter** <i@izs.me> * [lxe](https://github.com/lxe) - **Aleksey Smolenchuk** <lxe@lxe.co> +* [matthewloring](https://github.com/matthewloring) - +**Matthew Loring** <mattloring@google.com> * [monsanto](https://github.com/monsanto) - **Christopher Monsanto** <chris@monsan.to> * [Olegas](https://github.com/Olegas) - diff --git a/benchmark/buffers/buffer-read-float.js b/benchmark/buffers/buffer-read-float.js new file mode 100644 index 00000000000000..5dda2486c6711a --- /dev/null +++ b/benchmark/buffers/buffer-read-float.js @@ -0,0 +1,46 @@ +'use strict'; +const common = require('../common.js'); + +const bench = common.createBenchmark(main, { + noAssert: ['false', 'true'], + type: ['Double', 'Float'], + endian: ['BE', 'LE'], + value: ['zero', 'big', 'small', 'inf', 'nan'], + millions: [1] +}); + +function main(conf) { + const noAssert = conf.noAssert === 'true'; + const len = +conf.millions * 1e6; + const buff = Buffer.alloc(8); + const type = conf.type || 'Double'; + const endian = conf.endian; + const fn = `read${type}${endian}`; + const values = { + Double: { + zero: 0, + big: 2 ** 1023, + small: 2 ** -1074, + inf: Infinity, + nan: NaN, + }, + Float: { + zero: 0, + big: 2 ** 127, + small: 2 ** -149, + inf: Infinity, + nan: NaN, + }, + }; + const value = values[type][conf.value]; + + buff[`write${type}${endian}`](value, 0, noAssert); + const testFunction = new Function('buff', ` + for (var i = 0; i !== ${len}; i++) { + buff.${fn}(0, ${JSON.stringify(noAssert)}); + } + `); + bench.start(); + testFunction(buff); + bench.end(len / 1e6); +} diff --git a/benchmark/fs/read-stream-throughput.js b/benchmark/fs/read-stream-throughput.js index 162cef6864a686..e0dc7edc05ea3e 100644 --- a/benchmark/fs/read-stream-throughput.js +++ b/benchmark/fs/read-stream-throughput.js @@ -3,7 +3,7 @@ const path = require('path'); const common = require('../common.js'); -const filename = path.resolve(__dirname, +const filename = path.resolve(process.env.NODE_TMPDIR || __dirname, `.removeme-benchmark-garbage-${process.pid}`); const fs = require('fs'); const assert = require('assert'); diff --git a/benchmark/fs/readfile.js b/benchmark/fs/readfile.js index 82479ff14e5f68..7c55073fe0f017 100644 --- a/benchmark/fs/readfile.js +++ b/benchmark/fs/readfile.js @@ -5,7 +5,7 @@ const path = require('path'); const common = require('../common.js'); -const filename = path.resolve(__dirname, +const filename = path.resolve(process.env.NODE_TMPDIR || __dirname, `.removeme-benchmark-garbage-${process.pid}`); const fs = require('fs'); diff --git a/benchmark/fs/write-stream-throughput.js b/benchmark/fs/write-stream-throughput.js index 5c6464fdbb2cbb..08f059156f2cd9 100644 --- a/benchmark/fs/write-stream-throughput.js +++ b/benchmark/fs/write-stream-throughput.js @@ -3,7 +3,7 @@ const path = require('path'); const common = require('../common.js'); -const filename = path.resolve(__dirname, +const filename = path.resolve(process.env.NODE_TMPDIR || __dirname, `.removeme-benchmark-garbage-${process.pid}`); const fs = require('fs'); @@ -41,10 +41,6 @@ function main(conf) { var started = false; var ending = false; var ended = false; - setTimeout(function() { - ending = true; - f.end(); - }, dur * 1000); var f = fs.createWriteStream(filename); f.on('drain', write); @@ -66,6 +62,10 @@ function main(conf) { if (!started) { started = true; + setTimeout(function() { + ending = true; + f.end(); + }, dur * 1000); bench.start(); } diff --git a/benchmark/http/upgrade.js b/benchmark/http/upgrade.js new file mode 100644 index 00000000000000..0feaecc8ff19e6 --- /dev/null +++ b/benchmark/http/upgrade.js @@ -0,0 +1,53 @@ +'use strict'; + +const common = require('../common.js'); +const PORT = common.PORT; +const net = require('net'); + +const bench = common.createBenchmark(main, { + n: [5, 1000] +}); + +const reqData = 'GET / HTTP/1.1\r\n' + + 'Upgrade: WebSocket\r\n' + + 'Connection: Upgrade\r\n' + + '\r\n' + + 'WjN}|M(6'; + +const resData = 'HTTP/1.1 101 Web Socket Protocol Handshake\r\n' + + 'Upgrade: WebSocket\r\n' + + 'Connection: Upgrade\r\n' + + '\r\n\r\n'; + +function main({ n }) { + process.env.PORT = PORT; + var server = require('../fixtures/simple-http-server.js') + .listen(common.PORT) + .on('listening', function() { + bench.start(); + doBench(server.address(), n, function() { + bench.end(n); + server.close(); + }); + }) + .on('upgrade', function(req, socket, upgradeHead) { + socket.resume(); + socket.write(resData); + socket.end(); + }); +} + +function doBench(address, count, done) { + if (count === 0) { + done(); + return; + } + + const conn = net.createConnection(address.port); + conn.write(reqData); + conn.resume(); + + conn.on('end', function() { + doBench(address, count - 1, done); + }); +} diff --git a/benchmark/misc/arguments.js b/benchmark/misc/arguments.js new file mode 100644 index 00000000000000..2e5df6188b07f5 --- /dev/null +++ b/benchmark/misc/arguments.js @@ -0,0 +1,59 @@ +'use strict'; + +const { createBenchmark } = require('../common.js'); +const { format } = require('util'); + +const methods = [ + 'restAndSpread', + 'argumentsAndApply', + 'restAndApply', + 'predefined' +]; + +const bench = createBenchmark(main, { + method: methods, + n: [1e6] +}); + +function usingRestAndSpread(...args) { + format(...args); +} + +function usingRestAndApply(...args) { + format.apply(null, args); +} + +function usingArgumentsAndApply() { + format.apply(null, arguments); +} + +function usingPredefined() { + format('part 1', 'part', 2, 'part 3', 'part', 4); +} + +function main({ n, method, args }) { + var fn; + switch (method) { + // '' is a default case for tests + case '': + case 'restAndSpread': + fn = usingRestAndSpread; + break; + case 'restAndApply': + fn = usingRestAndApply; + break; + case 'argumentsAndApply': + fn = usingArgumentsAndApply; + break; + case 'predefined': + fn = usingPredefined; + break; + default: + throw new Error(`Unexpected method "${method}"`); + } + + bench.start(); + for (var i = 0; i < n; i++) + fn('part 1', 'part', 2, 'part 3', 'part', 4); + bench.end(n); +} diff --git a/benchmark/misc/console.js b/benchmark/misc/console.js deleted file mode 100644 index ab938168ac30c4..00000000000000 --- a/benchmark/misc/console.js +++ /dev/null @@ -1,126 +0,0 @@ -'use strict'; - -const common = require('../common.js'); -const assert = require('assert'); -const Writable = require('stream').Writable; -const util = require('util'); - -const methods = [ - 'restAndSpread', - 'argumentsAndApply', - 'restAndApply', - 'restAndConcat' -]; - -const bench = common.createBenchmark(main, { - method: methods, - concat: [1, 0], - n: [1000000] -}); - -const nullStream = createNullStream(); - -function usingRestAndConcat(...args) { - nullStream.write(`this is ${args[0]} of ${args[1]}\n`); -} - -function usingRestAndSpreadTS(...args) { - nullStream.write(`${util.format(...args)}\n`); -} - -function usingRestAndApplyTS(...args) { - nullStream.write(`${util.format.apply(null, args)}\n`); -} - -function usingArgumentsAndApplyTS() { - nullStream.write(`${util.format.apply(null, arguments)}\n`); -} - -function usingRestAndSpreadC(...args) { - nullStream.write(`${util.format(...args)}\n`); -} - -function usingRestAndApplyC(...args) { - nullStream.write(`${util.format.apply(null, args)}\n`); -} - -function usingArgumentsAndApplyC() { - nullStream.write(`${util.format.apply(null, arguments)}\n`); -} - -function runUsingRestAndConcat(n) { - - var i = 0; - bench.start(); - for (; i < n; i++) - usingRestAndConcat('a', 1); - bench.end(n); -} - -function runUsingRestAndSpread(n, concat) { - - const method = concat ? usingRestAndSpreadC : usingRestAndSpreadTS; - - var i = 0; - bench.start(); - for (; i < n; i++) - method('this is %s of %d', 'a', 1); - bench.end(n); -} - -function runUsingRestAndApply(n, concat) { - - const method = concat ? usingRestAndApplyC : usingRestAndApplyTS; - - var i = 0; - bench.start(); - for (; i < n; i++) - method('this is %s of %d', 'a', 1); - bench.end(n); -} - -function runUsingArgumentsAndApply(n, concat) { - - const method = concat ? usingArgumentsAndApplyC : usingArgumentsAndApplyTS; - - var i = 0; - bench.start(); - for (; i < n; i++) - method('this is %s of %d', 'a', 1); - bench.end(n); -} - -function main(conf) { - const n = +conf.n; - switch (conf.method) { - // '' is a default case for tests - case '': - case 'restAndSpread': - runUsingRestAndSpread(n, conf.concat); - break; - case 'restAndApply': - runUsingRestAndApply(n, conf.concat); - break; - case 'argumentsAndApply': - runUsingArgumentsAndApply(n, conf.concat); - break; - case 'restAndConcat': - if (conf.concat) - runUsingRestAndConcat(n); - break; - default: - throw new Error('Unexpected method'); - } -} - -function createNullStream() { - // Used to approximate /dev/null - function NullStream() { - Writable.call(this, {}); - } - util.inherits(NullStream, Writable); - NullStream.prototype._write = function(cb) { - assert.strictEqual(cb.toString(), 'this is a of 1\n'); - }; - return new NullStream(); -} diff --git a/common.gypi b/common.gypi index 0d9529f3ad2cc5..0d96ca77b3cc70 100644 --- a/common.gypi +++ b/common.gypi @@ -27,7 +27,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.15', + 'v8_embedder_string': '-node.16', # Enable disassembler for `--print-code` v8 options 'v8_enable_disassembler': 1, diff --git a/deps/nghttp2/lib/CMakeLists.txt b/deps/nghttp2/lib/CMakeLists.txt index 7ef37ed85cc628..0846d06789a0f1 100644 --- a/deps/nghttp2/lib/CMakeLists.txt +++ b/deps/nghttp2/lib/CMakeLists.txt @@ -44,6 +44,10 @@ set_target_properties(nghttp2 PROPERTIES VERSION ${LT_VERSION} SOVERSION ${LT_SOVERSION} C_VISIBILITY_PRESET hidden ) +target_include_directories(nghttp2 INTERFACE + "${CMAKE_CURRENT_BINARY_DIR}/includes" + "${CMAKE_CURRENT_SOURCE_DIR}/includes" + ) if(HAVE_CUNIT) # Static library (for unittests because of symbol visibility) diff --git a/deps/nghttp2/lib/includes/nghttp2/nghttp2.h b/deps/nghttp2/lib/includes/nghttp2/nghttp2.h index 5696a2ef633653..13cda9f29e28f5 100644 --- a/deps/nghttp2/lib/includes/nghttp2/nghttp2.h +++ b/deps/nghttp2/lib/includes/nghttp2/nghttp2.h @@ -387,6 +387,11 @@ typedef enum { * Indicates that a processing was canceled. */ NGHTTP2_ERR_CANCEL = -535, + /** + * When a local endpoint expects to receive SETTINGS frame, it + * receives an other type of frame. + */ + NGHTTP2_ERR_SETTINGS_EXPECTED = -536, /** * The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is * under unexpected condition and processing was terminated (e.g., @@ -1987,6 +1992,9 @@ typedef ssize_t (*nghttp2_pack_extension_callback)(nghttp2_session *session, * of length |len|. |len| does not include the sentinel NULL * character. * + * This function is deprecated. The new application should use + * :type:`nghttp2_error_callback2`. + * * The format of error message may change between nghttp2 library * versions. The application should not depend on the particular * format. @@ -2003,6 +2011,33 @@ typedef ssize_t (*nghttp2_pack_extension_callback)(nghttp2_session *session, typedef int (*nghttp2_error_callback)(nghttp2_session *session, const char *msg, size_t len, void *user_data); +/** + * @functypedef + * + * Callback function invoked when library provides the error code, and + * message. This callback is solely for debugging purpose. + * |lib_error_code| is one of error code defined in + * :enum:`nghttp2_error`. The |msg| is typically NULL-terminated + * string of length |len|, and intended for human consumption. |len| + * does not include the sentinel NULL character. + * + * The format of error message may change between nghttp2 library + * versions. The application should not depend on the particular + * format. + * + * Normally, application should return 0 from this callback. If fatal + * error occurred while doing something in this callback, application + * should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, + * library will return immediately with return value + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if nonzero value + * is returned from this callback, they are treated as + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, but application should not + * rely on this details. + */ +typedef int (*nghttp2_error_callback2)(nghttp2_session *session, + int lib_error_code, const char *msg, + size_t len, void *user_data); + struct nghttp2_session_callbacks; /** @@ -2267,10 +2302,30 @@ nghttp2_session_callbacks_set_on_extension_chunk_recv_callback( * * Sets callback function invoked when library tells error message to * the application. + * + * This function is deprecated. The new application should use + * `nghttp2_session_callbacks_set_error_callback2()`. + * + * If both :type:`nghttp2_error_callback` and + * :type:`nghttp2_error_callback2` are set, the latter takes + * precedence. */ NGHTTP2_EXTERN void nghttp2_session_callbacks_set_error_callback( nghttp2_session_callbacks *cbs, nghttp2_error_callback error_callback); +/** + * @function + * + * Sets callback function invoked when library tells error code, and + * message to the application. + * + * If both :type:`nghttp2_error_callback` and + * :type:`nghttp2_error_callback2` are set, the latter takes + * precedence. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_error_callback2( + nghttp2_session_callbacks *cbs, nghttp2_error_callback2 error_callback2); + /** * @functypedef * @@ -4702,8 +4757,8 @@ nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater, * * After this function returns, it is safe to delete the |nva|. * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: + * This function returns the number of bytes written to |buf| if it + * succeeds, or one of the following negative error codes: * * :enum:`NGHTTP2_ERR_NOMEM` * Out of memory. @@ -4734,8 +4789,8 @@ NGHTTP2_EXTERN ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, * * After this function returns, it is safe to delete the |nva|. * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: + * This function returns the number of bytes written to |vec| if it + * succeeds, or one of the following negative error codes: * * :enum:`NGHTTP2_ERR_NOMEM` * Out of memory. diff --git a/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h b/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h index 38c48bf041f1e8..455706a5868b3a 100644 --- a/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h +++ b/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h @@ -29,7 +29,7 @@ * @macro * Version number of the nghttp2 library release */ -#define NGHTTP2_VERSION "1.25.0" +#define NGHTTP2_VERSION "1.29.0" /** * @macro @@ -37,6 +37,6 @@ * release. This is a 24 bit number with 8 bits for major number, 8 bits * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. */ -#define NGHTTP2_VERSION_NUM 0x011900 +#define NGHTTP2_VERSION_NUM 0x011d00 #endif /* NGHTTP2VER_H */ diff --git a/deps/nghttp2/lib/nghttp2_buf.h b/deps/nghttp2/lib/nghttp2_buf.h index 06ab1e4c630cc3..9f484a221acb5f 100644 --- a/deps/nghttp2/lib/nghttp2_buf.h +++ b/deps/nghttp2/lib/nghttp2_buf.h @@ -398,7 +398,7 @@ int nghttp2_bufs_advance(nghttp2_bufs *bufs); void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs); /* - * Returns nonzero if bufs->cur->next is not emtpy. + * Returns nonzero if bufs->cur->next is not empty. */ int nghttp2_bufs_next_present(nghttp2_bufs *bufs); diff --git a/deps/nghttp2/lib/nghttp2_callbacks.c b/deps/nghttp2/lib/nghttp2_callbacks.c index b6cf5957f01b59..3c38214859b17a 100644 --- a/deps/nghttp2/lib/nghttp2_callbacks.c +++ b/deps/nghttp2/lib/nghttp2_callbacks.c @@ -168,3 +168,8 @@ void nghttp2_session_callbacks_set_error_callback( nghttp2_session_callbacks *cbs, nghttp2_error_callback error_callback) { cbs->error_callback = error_callback; } + +void nghttp2_session_callbacks_set_error_callback2( + nghttp2_session_callbacks *cbs, nghttp2_error_callback2 error_callback2) { + cbs->error_callback2 = error_callback2; +} diff --git a/deps/nghttp2/lib/nghttp2_callbacks.h b/deps/nghttp2/lib/nghttp2_callbacks.h index 5967524e0c6493..b607bbb58b8e3d 100644 --- a/deps/nghttp2/lib/nghttp2_callbacks.h +++ b/deps/nghttp2/lib/nghttp2_callbacks.h @@ -119,6 +119,7 @@ struct nghttp2_session_callbacks { nghttp2_unpack_extension_callback unpack_extension_callback; nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback; nghttp2_error_callback error_callback; + nghttp2_error_callback2 error_callback2; }; #endif /* NGHTTP2_CALLBACKS_H */ diff --git a/deps/nghttp2/lib/nghttp2_frame.h b/deps/nghttp2/lib/nghttp2_frame.h index 891289f61bf5e7..35ca214a4a7a59 100644 --- a/deps/nghttp2/lib/nghttp2_frame.h +++ b/deps/nghttp2/lib/nghttp2_frame.h @@ -70,7 +70,9 @@ #define NGHTTP2_MAX_PADLEN 256 /* Union of extension frame payload */ -typedef union { nghttp2_ext_altsvc altsvc; } nghttp2_ext_frame_payload; +typedef union { + nghttp2_ext_altsvc altsvc; +} nghttp2_ext_frame_payload; void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd); diff --git a/deps/nghttp2/lib/nghttp2_hd.h b/deps/nghttp2/lib/nghttp2_hd.h index 458edafe4d5847..760bfbc357efdc 100644 --- a/deps/nghttp2/lib/nghttp2_hd.h +++ b/deps/nghttp2/lib/nghttp2_hd.h @@ -211,7 +211,9 @@ typedef struct { #define HD_MAP_SIZE 128 -typedef struct { nghttp2_hd_entry *table[HD_MAP_SIZE]; } nghttp2_hd_map; +typedef struct { + nghttp2_hd_entry *table[HD_MAP_SIZE]; +} nghttp2_hd_map; struct nghttp2_hd_deflater { nghttp2_hd_context ctx; @@ -313,7 +315,7 @@ void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater); * * This function expands |bufs| as necessary to store the result. If * buffers is full and the process still requires more space, this - * funtion fails and returns NGHTTP2_ERR_HEADER_COMP. + * function fails and returns NGHTTP2_ERR_HEADER_COMP. * * After this function returns, it is safe to delete the |nva|. * diff --git a/deps/nghttp2/lib/nghttp2_helper.c b/deps/nghttp2/lib/nghttp2_helper.c index b00c9073a92a13..3b282c7301f95b 100644 --- a/deps/nghttp2/lib/nghttp2_helper.c +++ b/deps/nghttp2/lib/nghttp2_helper.c @@ -322,6 +322,9 @@ const char *nghttp2_strerror(int error_code) { return "Internal error"; case NGHTTP2_ERR_CANCEL: return "Cancel"; + case NGHTTP2_ERR_SETTINGS_EXPECTED: + return "When a local endpoint expects to receive SETTINGS frame, it " + "receives an other type of frame"; case NGHTTP2_ERR_NOMEM: return "Out of memory"; case NGHTTP2_ERR_CALLBACK_FAILURE: diff --git a/deps/nghttp2/lib/nghttp2_outbound_item.h b/deps/nghttp2/lib/nghttp2_outbound_item.h index 8bda776bfe2728..89a8a92668dd5c 100644 --- a/deps/nghttp2/lib/nghttp2_outbound_item.h +++ b/deps/nghttp2/lib/nghttp2_outbound_item.h @@ -112,7 +112,7 @@ struct nghttp2_outbound_item { nghttp2_ext_frame_payload ext_frame_payload; nghttp2_aux_data aux_data; /* The priority used in priority comparion. Smaller is served - ealier. For PING, SETTINGS and non-DATA frames (excluding + earlier. For PING, SETTINGS and non-DATA frames (excluding response HEADERS frame) have dedicated cycle value defined above. For DATA frame, cycle is computed by taking into account of effective weight and frame payload length previously sent, so diff --git a/deps/nghttp2/lib/nghttp2_pq.h b/deps/nghttp2/lib/nghttp2_pq.h index 1426bef760132c..71cf96a14e0c77 100644 --- a/deps/nghttp2/lib/nghttp2_pq.h +++ b/deps/nghttp2/lib/nghttp2_pq.h @@ -35,7 +35,9 @@ /* Implementation of priority queue */ -typedef struct { size_t index; } nghttp2_pq_entry; +typedef struct { + size_t index; +} nghttp2_pq_entry; typedef struct { /* The pointer to the pointer to the item stored */ @@ -71,7 +73,7 @@ void nghttp2_pq_free(nghttp2_pq *pq); /* * Adds |item| to the priority queue |pq|. * - * This function returns 0 if it succeds, or one of the following + * This function returns 0 if it succeeds, or one of the following * negative error codes: * * NGHTTP2_ERR_NOMEM diff --git a/deps/nghttp2/lib/nghttp2_queue.h b/deps/nghttp2/lib/nghttp2_queue.h index d872b07bde961c..c7eb753ca92182 100644 --- a/deps/nghttp2/lib/nghttp2_queue.h +++ b/deps/nghttp2/lib/nghttp2_queue.h @@ -36,7 +36,9 @@ typedef struct nghttp2_queue_cell { struct nghttp2_queue_cell *next; } nghttp2_queue_cell; -typedef struct { nghttp2_queue_cell *front, *back; } nghttp2_queue; +typedef struct { + nghttp2_queue_cell *front, *back; +} nghttp2_queue; void nghttp2_queue_init(nghttp2_queue *queue); void nghttp2_queue_free(nghttp2_queue *queue); diff --git a/deps/nghttp2/lib/nghttp2_session.c b/deps/nghttp2/lib/nghttp2_session.c index 4bc94cbb1982ad..b14ed77a25c293 100644 --- a/deps/nghttp2/lib/nghttp2_session.c +++ b/deps/nghttp2/lib/nghttp2_session.c @@ -148,14 +148,16 @@ static int check_ext_type_set(const uint8_t *ext_types, uint8_t type) { } static int session_call_error_callback(nghttp2_session *session, - const char *fmt, ...) { + int lib_error_code, const char *fmt, + ...) { size_t bufsize; va_list ap; char *buf; int rv; nghttp2_mem *mem; - if (!session->callbacks.error_callback) { + if (!session->callbacks.error_callback && + !session->callbacks.error_callback2) { return 0; } @@ -189,8 +191,13 @@ static int session_call_error_callback(nghttp2_session *session, return 0; } - rv = session->callbacks.error_callback(session, buf, (size_t)rv, - session->user_data); + if (session->callbacks.error_callback2) { + rv = session->callbacks.error_callback2(session, lib_error_code, buf, + (size_t)rv, session->user_data); + } else { + rv = session->callbacks.error_callback(session, buf, (size_t)rv, + session->user_data); + } nghttp2_mem_free(mem, buf); @@ -541,9 +548,8 @@ static int session_new(nghttp2_session **session_ptr, if (nghttp2_enable_strict_preface) { nghttp2_inbound_frame *iframe = &(*session_ptr)->iframe; - if (server && - ((*session_ptr)->opt_flags & NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC) == - 0) { + if (server && ((*session_ptr)->opt_flags & + NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC) == 0) { iframe->state = NGHTTP2_IB_READ_CLIENT_MAGIC; iframe->payloadleft = NGHTTP2_CLIENT_MAGIC_LEN; } else { @@ -2183,7 +2189,7 @@ static int session_prep_frame(nghttp2_session *session, closed. */ stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - /* predicte should fail if stream is NULL. */ + /* predicate should fail if stream is NULL. */ rv = session_predicate_push_promise_send(session, stream); if (rv != 0) { return rv; @@ -2411,19 +2417,16 @@ static int session_close_stream_on_goaway(nghttp2_session *session, nghttp2_stream *stream, *next_stream; nghttp2_close_stream_on_goaway_arg arg = {session, NULL, last_stream_id, incoming}; - uint32_t error_code; rv = nghttp2_map_each(&session->streams, find_stream_on_goaway_func, &arg); assert(rv == 0); - error_code = - session->server && incoming ? NGHTTP2_REFUSED_STREAM : NGHTTP2_CANCEL; - stream = arg.head; while (stream) { next_stream = stream->closed_next; stream->closed_next = NULL; - rv = nghttp2_session_close_stream(session, stream->stream_id, error_code); + rv = nghttp2_session_close_stream(session, stream->stream_id, + NGHTTP2_REFUSED_STREAM); /* stream may be deleted here */ @@ -3608,7 +3611,7 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame, nv.name->base, (int)nv.value->len, nv.value->base); rv2 = session_call_error_callback( - session, + session, NGHTTP2_ERR_HTTP_HEADER, "Ignoring received invalid HTTP header field: frame type: " "%u, stream: %d, name: [%.*s], value: [%.*s]", frame->hd.type, frame->hd.stream_id, (int)nv.name->len, @@ -3626,8 +3629,9 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame, nv.name->base, (int)nv.value->len, nv.value->base); rv = session_call_error_callback( - session, "Invalid HTTP header field was received: frame type: " - "%u, stream: %d, name: [%.*s], value: [%.*s]", + session, NGHTTP2_ERR_HTTP_HEADER, + "Invalid HTTP header field was received: frame type: " + "%u, stream: %d, name: [%.*s], value: [%.*s]", frame->hd.type, frame->hd.stream_id, (int)nv.name->len, nv.name->base, (int)nv.value->len, nv.value->base); @@ -3781,7 +3785,7 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session, session, frame, NGHTTP2_ERR_PROTO, "request HEADERS: stream_id == 0"); } - /* If client recieves idle stream from server, it is invalid + /* If client receives idle stream from server, it is invalid regardless stream ID is even or odd. This is because client is not expected to receive request from server. */ if (!session->server) { @@ -5345,9 +5349,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, iframe->state = NGHTTP2_IB_IGN_ALL; rv = session_call_error_callback( - session, "Remote peer returned unexpected data while we expected " - "SETTINGS frame. Perhaps, peer does not support HTTP/2 " - "properly."); + session, NGHTTP2_ERR_SETTINGS_EXPECTED, + "Remote peer returned unexpected data while we expected " + "SETTINGS frame. Perhaps, peer does not support HTTP/2 " + "properly."); if (nghttp2_is_fatal(rv)) { return rv; @@ -5588,13 +5593,13 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, if (iframe->payloadleft) { nghttp2_settings_entry *min_header_table_size_entry; - /* We allocate iv with addtional one entry, to store the + /* We allocate iv with additional one entry, to store the minimum header table size. */ iframe->max_niv = iframe->frame.hd.length / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH + 1; - iframe->iv = nghttp2_mem_malloc( - mem, sizeof(nghttp2_settings_entry) * iframe->max_niv); + iframe->iv = nghttp2_mem_malloc(mem, sizeof(nghttp2_settings_entry) * + iframe->max_niv); if (!iframe->iv) { return NGHTTP2_ERR_NOMEM; diff --git a/deps/nghttp2/lib/nghttp2_session.h b/deps/nghttp2/lib/nghttp2_session.h index 3e1467f6a356d7..c7cb27d77c1e25 100644 --- a/deps/nghttp2/lib/nghttp2_session.h +++ b/deps/nghttp2/lib/nghttp2_session.h @@ -319,7 +319,7 @@ struct nghttp2_session { uint8_t pending_enable_push; /* Nonzero if the session is server side. */ uint8_t server; - /* Flags indicating GOAWAY is sent and/or recieved. The flags are + /* Flags indicating GOAWAY is sent and/or received. The flags are composed by bitwise OR-ing nghttp2_goaway_flag. */ uint8_t goaway_flags; /* This flag is used to reduce excessive queuing of WINDOW_UPDATE to @@ -722,7 +722,7 @@ int nghttp2_session_on_goaway_received(nghttp2_session *session, nghttp2_frame *frame); /* - * Called when WINDOW_UPDATE is recieved, assuming |frame| is properly + * Called when WINDOW_UPDATE is received, assuming |frame| is properly * initialized. * * This function returns 0 if it succeeds, or one of the following @@ -737,7 +737,7 @@ int nghttp2_session_on_window_update_received(nghttp2_session *session, nghttp2_frame *frame); /* - * Called when ALTSVC is recieved, assuming |frame| is properly + * Called when ALTSVC is received, assuming |frame| is properly * initialized. * * This function returns 0 if it succeeds, or one of the following diff --git a/deps/nghttp2/lib/nghttp2_stream.c b/deps/nghttp2/lib/nghttp2_stream.c index 8dee6ef660983c..eccd3174ef7bda 100644 --- a/deps/nghttp2/lib/nghttp2_stream.c +++ b/deps/nghttp2/lib/nghttp2_stream.c @@ -366,8 +366,9 @@ static void check_queued(nghttp2_stream *stream) { } } if (queued == 0) { - fprintf(stderr, "stream(%p)=%d, stream->queued == 1, and " - "!stream_active(), but no descendants is queued\n", + fprintf(stderr, + "stream(%p)=%d, stream->queued == 1, and " + "!stream_active(), but no descendants is queued\n", stream, stream->stream_id); assert(0); } @@ -378,9 +379,10 @@ static void check_queued(nghttp2_stream *stream) { } } else { if (stream_active(stream) || !nghttp2_pq_empty(&stream->obq)) { - fprintf(stderr, "stream(%p) = %d, stream->queued == 0, but " - "stream_active(stream) == %d and " - "nghttp2_pq_size(&stream->obq) = %zu\n", + fprintf(stderr, + "stream(%p) = %d, stream->queued == 0, but " + "stream_active(stream) == %d and " + "nghttp2_pq_size(&stream->obq) = %zu\n", stream, stream->stream_id, stream_active(stream), nghttp2_pq_size(&stream->obq)); assert(0); diff --git a/deps/v8/src/builtins/arm/builtins-arm.cc b/deps/v8/src/builtins/arm/builtins-arm.cc index 0af87f2c8ac70f..7ca98251a91630 100644 --- a/deps/v8/src/builtins/arm/builtins-arm.cc +++ b/deps/v8/src/builtins/arm/builtins-arm.cc @@ -1073,22 +1073,15 @@ static void MaybeTailCallOptimizedCodeSlot(MacroAssembler* masm, Runtime::kCompileOptimized_Concurrent); { - // Otherwise, the marker is InOptimizationQueue. + // Otherwise, the marker is InOptimizationQueue, so fall through hoping + // that an interrupt will eventually update the slot with optimized code. if (FLAG_debug_code) { __ cmp( optimized_code_entry, Operand(Smi::FromEnum(OptimizationMarker::kInOptimizationQueue))); __ Assert(eq, kExpectedOptimizationSentinel); } - // Checking whether the queued function is ready for install is - // optional, since we come across interrupts and stack checks elsewhere. - // However, not checking may delay installing ready functions, and - // always checking would be quite expensive. A good compromise is to - // first check against stack limit as a cue for an interrupt signal. - __ LoadRoot(scratch2, Heap::kStackLimitRootIndex); - __ cmp(sp, Operand(scratch2)); - __ b(hs, &fallthrough); - GenerateTailCallToReturnedCode(masm, Runtime::kTryInstallOptimizedCode); + __ jmp(&fallthrough); } } diff --git a/deps/v8/src/builtins/arm64/builtins-arm64.cc b/deps/v8/src/builtins/arm64/builtins-arm64.cc index 03a4995f751696..ca8da67b852432 100644 --- a/deps/v8/src/builtins/arm64/builtins-arm64.cc +++ b/deps/v8/src/builtins/arm64/builtins-arm64.cc @@ -1084,22 +1084,15 @@ static void MaybeTailCallOptimizedCodeSlot(MacroAssembler* masm, Runtime::kCompileOptimized_Concurrent); { - // Otherwise, the marker is InOptimizationQueue. + // Otherwise, the marker is InOptimizationQueue, so fall through hoping + // that an interrupt will eventually update the slot with optimized code. if (FLAG_debug_code) { __ Cmp( optimized_code_entry, Operand(Smi::FromEnum(OptimizationMarker::kInOptimizationQueue))); __ Assert(eq, kExpectedOptimizationSentinel); } - - // Checking whether the queued function is ready for install is optional, - // since we come across interrupts and stack checks elsewhere. However, - // not checking may delay installing ready functions, and always checking - // would be quite expensive. A good compromise is to first check against - // stack limit as a cue for an interrupt signal. - __ CompareRoot(masm->StackPointer(), Heap::kStackLimitRootIndex); - __ B(hs, &fallthrough); - GenerateTailCallToReturnedCode(masm, Runtime::kTryInstallOptimizedCode); + __ B(&fallthrough); } } diff --git a/deps/v8/src/builtins/ia32/builtins-ia32.cc b/deps/v8/src/builtins/ia32/builtins-ia32.cc index 03db488b7e10f0..9d3178dc89c08c 100644 --- a/deps/v8/src/builtins/ia32/builtins-ia32.cc +++ b/deps/v8/src/builtins/ia32/builtins-ia32.cc @@ -715,24 +715,15 @@ static void MaybeTailCallOptimizedCodeSlot(MacroAssembler* masm, Runtime::kCompileOptimized_Concurrent); { - // Otherwise, the marker is InOptimizationQueue. + // Otherwise, the marker is InOptimizationQueue, so fall through hoping + // that an interrupt will eventually update the slot with optimized code. if (FLAG_debug_code) { __ cmp( optimized_code_entry, Immediate(Smi::FromEnum(OptimizationMarker::kInOptimizationQueue))); __ Assert(equal, kExpectedOptimizationSentinel); } - - // Checking whether the queued function is ready for install is optional, - // since we come across interrupts and stack checks elsewhere. However, - // not checking may delay installing ready functions, and always checking - // would be quite expensive. A good compromise is to first check against - // stack limit as a cue for an interrupt signal. - ExternalReference stack_limit = - ExternalReference::address_of_stack_limit(masm->isolate()); - __ cmp(esp, Operand::StaticVariable(stack_limit)); - __ j(above_equal, &fallthrough); - GenerateTailCallToReturnedCode(masm, Runtime::kTryInstallOptimizedCode); + __ jmp(&fallthrough); } } diff --git a/deps/v8/src/builtins/mips/builtins-mips.cc b/deps/v8/src/builtins/mips/builtins-mips.cc index b280c161d6386b..af214cb4b986fc 100644 --- a/deps/v8/src/builtins/mips/builtins-mips.cc +++ b/deps/v8/src/builtins/mips/builtins-mips.cc @@ -1052,21 +1052,14 @@ static void MaybeTailCallOptimizedCodeSlot(MacroAssembler* masm, Runtime::kCompileOptimized_Concurrent); { - // Otherwise, the marker is InOptimizationQueue. + // Otherwise, the marker is InOptimizationQueue, so fall through hoping + // that an interrupt will eventually update the slot with optimized code. if (FLAG_debug_code) { __ Assert( eq, kExpectedOptimizationSentinel, optimized_code_entry, Operand(Smi::FromEnum(OptimizationMarker::kInOptimizationQueue))); } - - // Checking whether the queued function is ready for install is optional, - // since we come across interrupts and stack checks elsewhere. However, - // not checking may delay installing ready functions, and always checking - // would be quite expensive. A good compromise is to first check against - // stack limit as a cue for an interrupt signal. - __ LoadRoot(at, Heap::kStackLimitRootIndex); - __ Branch(&fallthrough, hs, sp, Operand(at)); - GenerateTailCallToReturnedCode(masm, Runtime::kTryInstallOptimizedCode); + __ jmp(&fallthrough); } } diff --git a/deps/v8/src/builtins/mips64/builtins-mips64.cc b/deps/v8/src/builtins/mips64/builtins-mips64.cc index b65a796785c7c2..fd014cc90257a8 100644 --- a/deps/v8/src/builtins/mips64/builtins-mips64.cc +++ b/deps/v8/src/builtins/mips64/builtins-mips64.cc @@ -1054,21 +1054,14 @@ static void MaybeTailCallOptimizedCodeSlot(MacroAssembler* masm, Runtime::kCompileOptimized_Concurrent); { - // Otherwise, the marker is InOptimizationQueue. + // Otherwise, the marker is InOptimizationQueue, so fall through hoping + // that an interrupt will eventually update the slot with optimized code. if (FLAG_debug_code) { __ Assert( eq, kExpectedOptimizationSentinel, optimized_code_entry, Operand(Smi::FromEnum(OptimizationMarker::kInOptimizationQueue))); } - - // Checking whether the queued function is ready for install is optional, - // since we come across interrupts and stack checks elsewhere. However, - // not checking may delay installing ready functions, and always checking - // would be quite expensive. A good compromise is to first check against - // stack limit as a cue for an interrupt signal. - __ LoadRoot(t0, Heap::kStackLimitRootIndex); - __ Branch(&fallthrough, hs, sp, Operand(t0)); - GenerateTailCallToReturnedCode(masm, Runtime::kTryInstallOptimizedCode); + __ jmp(&fallthrough); } } diff --git a/deps/v8/src/builtins/ppc/builtins-ppc.cc b/deps/v8/src/builtins/ppc/builtins-ppc.cc index 646f7f62bcd552..8a5ec14b421870 100644 --- a/deps/v8/src/builtins/ppc/builtins-ppc.cc +++ b/deps/v8/src/builtins/ppc/builtins-ppc.cc @@ -1081,23 +1081,15 @@ static void MaybeTailCallOptimizedCodeSlot(MacroAssembler* masm, Runtime::kCompileOptimized_Concurrent); { - // Otherwise, the marker is InOptimizationQueue. + // Otherwise, the marker is InOptimizationQueue, so fall through hoping + // that an interrupt will eventually update the slot with optimized code. if (FLAG_debug_code) { __ CmpSmiLiteral( optimized_code_entry, Smi::FromEnum(OptimizationMarker::kInOptimizationQueue), r0); __ Assert(eq, kExpectedOptimizationSentinel); } - - // Checking whether the queued function is ready for install is optional, - // since we come across interrupts and stack checks elsewhere. However, - // not checking may delay installing ready functions, and always checking - // would be quite expensive. A good compromise is to first check against - // stack limit as a cue for an interrupt signal. - __ LoadRoot(ip, Heap::kStackLimitRootIndex); - __ cmpl(sp, ip); - __ bge(&fallthrough); - GenerateTailCallToReturnedCode(masm, Runtime::kTryInstallOptimizedCode); + __ b(&fallthrough); } } diff --git a/deps/v8/src/builtins/s390/builtins-s390.cc b/deps/v8/src/builtins/s390/builtins-s390.cc index c965805fc72fe7..c9800fa2879529 100644 --- a/deps/v8/src/builtins/s390/builtins-s390.cc +++ b/deps/v8/src/builtins/s390/builtins-s390.cc @@ -1081,22 +1081,15 @@ static void MaybeTailCallOptimizedCodeSlot(MacroAssembler* masm, Runtime::kCompileOptimized_Concurrent); { - // Otherwise, the marker is InOptimizationQueue. + // Otherwise, the marker is InOptimizationQueue, so fall through hoping + // that an interrupt will eventually update the slot with optimized code. if (FLAG_debug_code) { __ CmpSmiLiteral( optimized_code_entry, Smi::FromEnum(OptimizationMarker::kInOptimizationQueue), r0); __ Assert(eq, kExpectedOptimizationSentinel); } - - // Checking whether the queued function is ready for install is optional, - // since we come across interrupts and stack checks elsewhere. However, - // not checking may delay installing ready functions, and always checking - // would be quite expensive. A good compromise is to first check against - // stack limit as a cue for an interrupt signal. - __ CmpLogicalP(sp, RootMemOperand(Heap::kStackLimitRootIndex)); - __ bge(&fallthrough, Label::kNear); - GenerateTailCallToReturnedCode(masm, Runtime::kTryInstallOptimizedCode); + __ b(&fallthrough, Label::kNear); } } diff --git a/deps/v8/src/builtins/x64/builtins-x64.cc b/deps/v8/src/builtins/x64/builtins-x64.cc index 981bb65fd198df..047c128106c925 100644 --- a/deps/v8/src/builtins/x64/builtins-x64.cc +++ b/deps/v8/src/builtins/x64/builtins-x64.cc @@ -798,21 +798,14 @@ static void MaybeTailCallOptimizedCodeSlot(MacroAssembler* masm, Runtime::kCompileOptimized_Concurrent); { - // Otherwise, the marker is InOptimizationQueue. + // Otherwise, the marker is InOptimizationQueue, so fall through hoping + // that an interrupt will eventually update the slot with optimized code. if (FLAG_debug_code) { __ SmiCompare(optimized_code_entry, Smi::FromEnum(OptimizationMarker::kInOptimizationQueue)); __ Assert(equal, kExpectedOptimizationSentinel); } - - // Checking whether the queued function is ready for install is optional, - // since we come across interrupts and stack checks elsewhere. However, - // not checking may delay installing ready functions, and always checking - // would be quite expensive. A good compromise is to first check against - // stack limit as a cue for an interrupt signal. - __ CompareRoot(rsp, Heap::kStackLimitRootIndex); - __ j(above_equal, &fallthrough); - GenerateTailCallToReturnedCode(masm, Runtime::kTryInstallOptimizedCode); + __ jmp(&fallthrough); } } diff --git a/deps/v8/src/runtime/runtime-compiler.cc b/deps/v8/src/runtime/runtime-compiler.cc index 4b575932276218..fd2df5afe31652 100644 --- a/deps/v8/src/runtime/runtime-compiler.cc +++ b/deps/v8/src/runtime/runtime-compiler.cc @@ -340,27 +340,6 @@ RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) { return NULL; } - -RUNTIME_FUNCTION(Runtime_TryInstallOptimizedCode) { - HandleScope scope(isolate); - DCHECK_EQ(1, args.length()); - CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); - - // First check if this is a real stack overflow. - StackLimitCheck check(isolate); - if (check.JsHasOverflowed(kStackSpaceRequiredForCompilation * KB)) { - return isolate->StackOverflow(); - } - - // Only try to install optimized functions if the interrupt was InstallCode. - if (isolate->stack_guard()->CheckAndClearInstallCode()) { - isolate->optimizing_compile_dispatcher()->InstallOptimizedFunctions(); - } - - return (function->IsOptimized()) ? function->code() - : function->shared()->code(); -} - static Object* CompileGlobalEval(Isolate* isolate, Handle source, Handle outer_info, LanguageMode language_mode, diff --git a/deps/v8/src/runtime/runtime.h b/deps/v8/src/runtime/runtime.h index a78966f226ac8f..018bf6aa008a77 100644 --- a/deps/v8/src/runtime/runtime.h +++ b/deps/v8/src/runtime/runtime.h @@ -115,7 +115,6 @@ namespace internal { F(NotifyStubFailure, 0, 1) \ F(NotifyDeoptimized, 1, 1) \ F(CompileForOnStackReplacement, 1, 1) \ - F(TryInstallOptimizedCode, 1, 1) \ F(ResolvePossiblyDirectEval, 6, 1) \ F(InstantiateAsmJs, 4, 1) diff --git a/doc/STYLE_GUIDE.md b/doc/STYLE_GUIDE.md index d1bf5208595c20..8ea9c8fe81b732 100644 --- a/doc/STYLE_GUIDE.md +++ b/doc/STYLE_GUIDE.md @@ -9,9 +9,7 @@ * The formatting described in `.editorconfig` is preferred. * A [plugin][] is available for some editors to automatically apply these rules. -* Mechanical issues, like spelling and grammar, should be identified by tools, - insofar as is possible. If not caught by a tool, they should be pointed out by - human reviewers. +* Changes to documentation should be checked with `make lint-md`. * American English spelling is preferred. "Capitalize" vs. "Capitalise", "color" vs. "colour", etc. * Use [serial commas][]. diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index 54bae4b1387088..e8cb9344c4c123 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -484,9 +484,8 @@ fs.open(path, 'r', (err, fd) => { }); ``` -It is important to note that the ID returned fom `executionAsyncId()` is related -to execution timing, not causality (which is covered by `triggerAsyncId()`). For -example: +The ID returned fom `executionAsyncId()` is related to execution timing, not +causality (which is covered by `triggerAsyncId()`). For example: ```js const server = net.createServer(function onConnection(conn) { @@ -526,7 +525,7 @@ const server = net.createServer((conn) => { ## JavaScript Embedder API -Library developers that handle their own asychronous resources performing tasks +Library developers that handle their own asynchronous resources performing tasks like I/O, connection pooling, or managing callback queues may use the `AsyncWrap` JavaScript API so that all the appropriate callbacks are called. @@ -538,9 +537,9 @@ own resources. The `init` hook will trigger when an `AsyncResource` is instantiated. -*Note*: It is important that `before`/`after` calls are unwound -in the same order they are called. Otherwise an unrecoverable exception -will occur and the process will abort. +*Note*: `before` and `after` calls must be unwound in the same order that they +are called. Otherwise, an unrecoverable exception will occur and the process +will abort. The following is an overview of the `AsyncResource` API. diff --git a/doc/api/buffer.md b/doc/api/buffer.md index bca6f92dda13aa..41b4e643055af2 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -1043,13 +1043,11 @@ changes: * `targetStart` {integer} The offset within `target` at which to begin comparison. **Default:** `0` * `targetEnd` {integer} The offset with `target` at which to end comparison - (not inclusive). Ignored when `targetStart` is `undefined`. - **Default:** `target.length` + (not inclusive). **Default:** `target.length` * `sourceStart` {integer} The offset within `buf` at which to begin comparison. - Ignored when `targetStart` is `undefined`. **Default:** `0` + **Default:** `0` * `sourceEnd` {integer} The offset within `buf` at which to end comparison - (not inclusive). Ignored when `targetStart` is `undefined`. - **Default:** [`buf.length`] + (not inclusive). **Default:** [`buf.length`] * Returns: {integer} Compares `buf` with `target` and returns a number indicating whether `buf` @@ -1119,9 +1117,9 @@ added: v0.1.90 * `targetStart` {integer} The offset within `target` at which to begin copying to. **Default:** `0` * `sourceStart` {integer} The offset within `buf` at which to begin copying from. - Ignored when `targetStart` is `undefined`. **Default:** `0` + **Default:** `0` * `sourceEnd` {integer} The offset within `buf` at which to stop copying (not - inclusive). Ignored when `sourceStart` is `undefined`. **Default:** [`buf.length`] + inclusive). **Default:** [`buf.length`] * Returns: {integer} The number of bytes copied. Copies data from a region of `buf` to a region in `target` even if the `target` diff --git a/doc/api/child_process.md b/doc/api/child_process.md index 84453ce1cfd8ef..2f86d5156fc438 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -623,7 +623,7 @@ pipes between the parent and child. The value is one of the following: have an underlying descriptor (file streams do not until the `'open'` event has occurred). 5. Positive integer - The integer value is interpreted as a file descriptor - that is is currently open in the parent process. It is shared with the child + that is currently open in the parent process. It is shared with the child process, similar to how {Stream} objects can be shared. 6. `null`, `undefined` - Use default value. For stdio fds 0, 1, and 2 (in other words, stdin, stdout, and stderr) a pipe is created. For fd 3 and up, the @@ -980,7 +980,7 @@ added: v0.1.90 * `signal` {string} -The `subprocess.kill()` methods sends a signal to the child process. If no +The `subprocess.kill()` method sends a signal to the child process. If no argument is given, the process will be sent the `'SIGTERM'` signal. See signal(7) for a list of available signals. diff --git a/doc/api/cluster.md b/doc/api/cluster.md index 7ab4d33dbd9ca8..016fdf6c185c68 100644 --- a/doc/api/cluster.md +++ b/doc/api/cluster.md @@ -722,6 +722,8 @@ changes: This can be a number, or a function that takes no arguments and returns a number. By default each worker gets its own port, incremented from the master's `process.debugPort`. + * `windowsHide` {boolean} Hide the forked processes console window that would + normally be created on Windows systems. **Default:** `false` After calling `.setupMaster()` (or `.fork()`) this settings object will contain the settings, including the default values. diff --git a/doc/api/console.md b/doc/api/console.md index 5722f362841484..84b7e2c11dac8e 100644 --- a/doc/api/console.md +++ b/doc/api/console.md @@ -402,11 +402,6 @@ console.timeEnd('100-elements'); // prints 100-elements: 225.438ms ``` -*Note*: As of Node.js v6.0.0, `console.timeEnd()` deletes the timer to avoid -leaking it. On older versions, the timer persisted. This allowed -`console.timeEnd()` to be called multiple times for the same label. This -functionality was unintended and is no longer supported. - ### console.trace([message][, ...args]) @@ -53,40 +49,43 @@ is not recommended in production environments. Experimental features are not subject to the Node.js Semantic Versioning model. ``` -*Note*: Caution must be used when making use of `Experimental` features, -particularly within modules that may be used as dependencies (or dependencies -of dependencies) within a Node.js application. End users may not be aware that -experimental features are being used, and therefore may experience unexpected -failures or behavioral changes when changes occur. To help avoid such surprises, -`Experimental` features may require a command-line flag to explicitly enable -them, or may cause a process warning to be emitted. By default, such warnings -are printed to `stderr` and may be handled by attaching a listener to the -`process.on('warning')` event. - ```txt Stability: 2 - Stable The API has proven satisfactory. Compatibility with the npm ecosystem is a high priority, and will not be broken unless absolutely necessary. ``` +*Note*: Caution must be used when making use of `Experimental` features, +particularly within modules that may be used as dependencies (or dependencies +of dependencies) within a Node.js application. End users may not be aware that +experimental features are being used, and therefore may experience unexpected +failures or behavior changes when API modifications occur. To help avoid such +surprises, `Experimental` features may require a command-line flag to +explicitly enable them, or may cause a process warning to be emitted. +By default, such warnings are printed to [`stderr`][] and may be handled by +attaching a listener to the [`process.on('warning')`][] event. + ## JSON Output + > Stability: 1 - Experimental -Every HTML file in the markdown has a corresponding JSON file with the -same data. - -This feature was added in Node.js v0.6.12. It is experimental. +Every `.html` document has a corresponding `.json` document presenting +the same information in a structured manner. This feature is +experimental, and added for the benefit of IDEs and other utilities that +wish to do programmatic things with the documentation. ## Syscalls and man pages System calls like open(2) and read(2) define the interface between user programs and the underlying operating system. Node functions which simply wrap a syscall, -like `fs.open()`, will document that. The docs link to the corresponding man +like [`fs.open()`][], will document that. The docs link to the corresponding man pages (short for manual pages) which describe how the syscalls work. -**Note:** some syscalls, like lchown(2), are BSD-specific. That means, for -example, that `fs.lchown()` only works on macOS and other BSD-derived systems, +Some syscalls, like lchown(2), are BSD-specific. That means, for +example, that [`fs.lchown()`][] only works on macOS and other BSD-derived systems, and is not available on Linux. Most Unix syscalls have Windows equivalents, but behavior may differ on Windows @@ -96,3 +95,7 @@ issue 4760](https://github.com/nodejs/node/issues/4760). [submit an issue]: https://github.com/nodejs/node/issues/new [the contributing guide]: https://github.com/nodejs/node/blob/master/CONTRIBUTING.md +[`stderr`]: process.html#process_process_stderr +[`process.on('warning')`]: process.html#process_event_warning +[`fs.open()`]: fs.html#fs_fs_open_path_flags_mode_callback +[`fs.lchown()`]: fs.html#fs_fs_lchown_path_uid_gid_callback diff --git a/doc/api/errors.md b/doc/api/errors.md index 4558bc6f3908d5..ac110a77445343 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -128,21 +128,22 @@ they are thrown *after* the calling code has already exited. Developers must refer to the documentation for each method to determine exactly how errors raised by those methods are propagated. -### Node.js style callbacks +### Error-first callbacks Most asynchronous methods exposed by the Node.js core API follow an idiomatic -pattern referred to as a "Node.js style callback". With this pattern, a -callback function is passed to the method as an argument. When the operation -either completes or an error is raised, the callback function is called with -the Error object (if any) passed as the first argument. If no error was raised, -the first argument will be passed as `null`. +pattern referred to as an _error-first callback_ (sometimes referred to as +a _Node.js style callback_). With this pattern, a callback function is passed +to the method as an argument. When the operation either completes or an error +is raised, the callback function is called with +the Error object (if any) passed as the first argument. If no error was +raised, the first argument will be passed as `null`. ```js const fs = require('fs'); -function nodeStyleCallback(err, data) { +function errorFirstCallback(err, data) { if (err) { console.error('There was an error', err); return; @@ -150,13 +151,13 @@ function nodeStyleCallback(err, data) { console.log(data); } -fs.readFile('/some/file/that/does-not-exist', nodeStyleCallback); -fs.readFile('/some/file/that/does-exist', nodeStyleCallback); +fs.readFile('/some/file/that/does-not-exist', errorFirstCallback); +fs.readFile('/some/file/that/does-exist', errorFirstCallback); ``` The JavaScript `try / catch` mechanism **cannot** be used to intercept errors generated by asynchronous APIs. A common mistake for beginners is to try to -use `throw` inside a Node.js style callback: +use `throw` inside an error-first callback: ```js // THIS WILL NOT WORK: @@ -311,11 +312,10 @@ location information will be displayed for that frame. Otherwise, the determined function name will be displayed with location information appended in parentheses. -It is important to note that frames are **only** generated for JavaScript -functions. If, for example, execution synchronously passes through a C++ addon -function called `cheetahify`, which itself calls a JavaScript function, the -frame representing the `cheetahify` call will **not** be present in the stack -traces: +Frames are only generated for JavaScript functions. If, for example, execution +synchronously passes through a C++ addon function called `cheetahify` which +itself calls a JavaScript function, the frame representing the `cheetahify` call +will not be present in the stack traces: ```js const cheetahify = require('./native-binding.node'); diff --git a/doc/api/esm.md b/doc/api/esm.md index ef9adbdc73f68d..08d3ea6b3060b9 100644 --- a/doc/api/esm.md +++ b/doc/api/esm.md @@ -206,7 +206,7 @@ export async function dynamicInstantiate(url) { ``` With the list of module exports provided upfront, the `execute` function will -then be called at the exact point of module evalutation order for that module +then be called at the exact point of module evaluation order for that module in the import tree. [Node.js EP for ES Modules]: https://github.com/nodejs/node-eps/blob/master/002-es-modules.md diff --git a/doc/api/events.md b/doc/api/events.md index c935b7de0f78b1..d0bf2c1897a923 100644 --- a/doc/api/events.md +++ b/doc/api/events.md @@ -175,7 +175,7 @@ added and `'removeListener'` when existing listeners are removed. added: v0.1.26 --> -* `eventName` {any} The name of the event being listened for +* `eventName` {string|symbol} The name of the event being listened for * `listener` {Function} The event handler function The `EventEmitter` instance will emit its own `'newListener'` event *before* @@ -219,7 +219,7 @@ changes: now yields the original listener function. --> -* `eventName` {any} The event name +* `eventName` {string|symbol} The event name * `listener` {Function} The event handler function The `'removeListener'` event is emitted *after* the `listener` is removed. @@ -287,7 +287,7 @@ Its `name` property is set to `'MaxListenersExceededWarning'`. -- `eventName` {any} +- `eventName` {string|symbol} - `listener` {Function} Alias for `emitter.on(eventName, listener)`. @@ -296,7 +296,7 @@ Alias for `emitter.on(eventName, listener)`. -- `eventName` {any} +- `eventName` {string|symbol} - `...args` {any} Synchronously calls each of the listeners registered for the event named @@ -340,7 +340,7 @@ set by [`emitter.setMaxListeners(n)`][] or defaults to added: v3.2.0 --> -* `eventName` {any} The name of the event being listened for +* `eventName` {string|symbol} The name of the event being listened for Returns the number of listeners listening to the event named `eventName`. @@ -353,7 +353,7 @@ changes: description: For listeners attached using `.once()` this returns the original listeners instead of wrapper functions now. --> -- `eventName` {any} +- `eventName` {string|symbol} Returns a copy of the array of listeners for the event named `eventName`. @@ -370,7 +370,7 @@ console.log(util.inspect(server.listeners('connection'))); added: v0.1.101 --> -* `eventName` {any} The name of the event. +* `eventName` {string|symbol} The name of the event. * `listener` {Function} The callback function Adds the `listener` function to the end of the listeners array for the @@ -406,7 +406,7 @@ myEE.emit('foo'); added: v0.3.0 --> -* `eventName` {any} The name of the event. +* `eventName` {string|symbol} The name of the event. * `listener` {Function} The callback function Adds a **one-time** `listener` function for the event named `eventName`. The @@ -439,7 +439,7 @@ myEE.emit('foo'); added: v6.0.0 --> -* `eventName` {any} The name of the event. +* `eventName` {string|symbol} The name of the event. * `listener` {Function} The callback function Adds the `listener` function to the *beginning* of the listeners array for the @@ -461,7 +461,7 @@ Returns a reference to the `EventEmitter`, so that calls can be chained. added: v6.0.0 --> -* `eventName` {any} The name of the event. +* `eventName` {string|symbol} The name of the event. * `listener` {Function} The callback function Adds a **one-time** `listener` function for the event named `eventName` to the @@ -480,7 +480,7 @@ Returns a reference to the `EventEmitter`, so that calls can be chained. -- `eventName` {any} +- `eventName` {string|symbol} Removes all listeners, or those of the specified `eventName`. @@ -494,7 +494,7 @@ Returns a reference to the `EventEmitter`, so that calls can be chained. -- `eventName` {any} +- `eventName` {string|symbol} - `listener` {Function} Removes the specified `listener` from the listener array for the event named @@ -578,7 +578,7 @@ Returns a reference to the `EventEmitter`, so that calls can be chained. -- `eventName` {any} +- `eventName` {string|symbol} Returns a copy of the array of listeners for the event named `eventName`, including any wrappers (such as those created by `.once`). diff --git a/doc/api/fs.md b/doc/api/fs.md index fb8d246f03d845..47491cf5a742c7 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -6,20 +6,23 @@ -File I/O is provided by simple wrappers around standard POSIX functions. To -use this module do `require('fs')`. All the methods have asynchronous and -synchronous forms. +The `fs` module provides an API for interacting with the file system in a +manner closely modeled around standard POSIX functions. + +To use this module: + +```js +const fs = require('fs'); +``` + +All file system operations have synchronous and asynchronous forms. The asynchronous form always takes a completion callback as its last argument. The arguments passed to the completion callback depend on the method, but the first argument is always reserved for an exception. If the operation was completed successfully, then the first argument will be `null` or `undefined`. -When using the synchronous form any exceptions are immediately thrown. -Exceptions may be handled using `try`/`catch`, or they may be allowed to -bubble up. - -Here is an example of the asynchronous version: +For example: ```js const fs = require('fs'); @@ -30,17 +33,25 @@ fs.unlink('/tmp/hello', (err) => { }); ``` -Here is the synchronous version: +Exceptions that occur using synchronous operations are thrown immediately and +may be handled using `try`/`catch`, or may be allowed to bubble up. + +For example: ```js const fs = require('fs'); -fs.unlinkSync('/tmp/hello'); -console.log('successfully deleted /tmp/hello'); +try { + fs.unlinkSync('/tmp/hello'); + console.log('successfully deleted /tmp/hello'); +} catch (err) { + // handle the error +} ``` -With the asynchronous methods there is no guaranteed ordering. So the -following is prone to error: +Note that there is no guaranteed ordering when using asynchronous methods. +So the following is prone to error because the `fs.stat()` operation may +complete before the `fs.rename()` operation. ```js fs.rename('/tmp/hello', '/tmp/world', (err) => { @@ -53,8 +64,8 @@ fs.stat('/tmp/world', (err, stats) => { }); ``` -It could be that `fs.stat` is executed before `fs.rename`. -The correct way to do this is to chain the callbacks. +To correctly order the operations, move the `fs.stat()` call into the callback +of the `fs.rename()` operation: ```js fs.rename('/tmp/hello', '/tmp/world', (err) => { @@ -70,9 +81,6 @@ In busy processes, the programmer is _strongly encouraged_ to use the asynchronous versions of these calls. The synchronous versions will block the entire process until they complete--halting all connections. -The relative path to a filename can be used. Remember, however, that this path -will be relative to `process.cwd()`. - While it is not recommended, most fs functions allow the callback argument to be omitted, in which case a default callback is used that rethrows errors. To get a trace to the original call site, set the `NODE_DEBUG` environment @@ -96,25 +104,63 @@ Error: EISDIR: illegal operation on a directory, read ``` +## File paths + +Most `fs` operations accept filepaths that may be specified in the form of +a string, a [`Buffer`][], or a [`URL`][] object using the `file:` protocol. + +String form paths are interpreted as UTF-8 character sequences identifying +the absolute or relative filename. Relative paths will be resolved relative +to the current working directory as specified by `process.cwd()`. + +Example using an absolute path on POSIX: + +```js +const fs = require('fs'); + +fs.open('/open/some/file.txt', 'r', (err, fd) => { + if (err) throw err; + fs.close(fd, (err) => { + if (err) throw err; + }); +}); +``` + +Example using a relative path on POSIX (relative to `process.cwd()`): + +```js +fs.open('file.txt', 'r', (err, fd) => { + if (err) throw err; + fs.close(fd, (err) => { + if (err) throw err; + }); +}); +``` + +Paths specified using a [`Buffer`][] are useful primarily on certain POSIX +operating systems that treat file paths as opaque byte sequences. On such +systems, it is possible for a single file path to contain sub-sequences that +use multiple character encodings. As with string paths, `Buffer` paths may +be relative or absolute: + +Example using an absolute path on POSIX: + +```js +fs.open(Buffer.from('/open/some/file.txt'), 'r', (err, fd) => { + if (err) throw err; + fs.close(fd, (err) => { + if (err) throw err; + }); +}); +``` + *Note:* On Windows Node.js follows the concept of per-drive working directory. This behavior can be observed when using a drive path without a backslash. For example `fs.readdirSync('c:\\')` can potentially return a different result than `fs.readdirSync('c:')`. For more information, see [this MSDN page][MSDN-Rel-Path]. -*Note:* On Windows, opening an existing hidden file using the `w` flag (either -through `fs.open` or `fs.writeFile`) will fail with `EPERM`. Existing hidden -files can be opened for writing with the `r+` flag. A call to `fs.ftruncate` can -be used to reset the file contents. - -## Threadpool Usage - -Note that all file system APIs except `fs.FSWatcher()` and those that are -explicitly synchronous use libuv's threadpool, which can have surprising and -negative performance implications for some applications, see the -[`UV_THREADPOOL_SIZE`][] documentation for more information. - -## WHATWG URL object support +### URL object support @@ -203,39 +249,65 @@ fs.readFileSync(new URL('file:///C:/path/%5c')); \ or / characters */ ``` -## Buffer API - +## File Descriptors + +On POSIX systems, for every process, the kernel maintains a table of currently +open files and resources. Each open file is assigned a simple numeric +identifier called a *file descriptor*. At the system-level, all file system +operations use these file descriptors to identify and track each specific +file. Windows systems use a different but conceptually similar mechanism for +tracking resources. To simplify things for users, Node.js abstracts away the +specific differences between operating systems and assigns all open files a +numeric file descriptor. + +The `fs.open()` method is used to allocate a new file descriptor. Once +allocated, the file descriptor may be used to read data from, write data to, +or request information about the file. + +```js +fs.open('/open/some/file.txt', 'r', (err, fd) => { + if (err) throw err; + fs.fstat(fd, (err, stat) => { + if (err) throw err; + // use stat + + // always close the file descriptor! + fs.close(fd, (err) => { + if (err) throw err; + }); + }); +}); +``` -`fs` functions support passing and receiving paths as both strings -and Buffers. The latter is intended to make it possible to work with -filesystems that allow for non-UTF-8 filenames. For most typical -uses, working with paths as Buffers will be unnecessary, as the string -API converts to and from UTF-8 automatically. +Most operating systems limit the number of file descriptors that may be open +at any given time so it is critical to close the descriptor when operations +are completed. Failure to do so will result in a memory leak that will +eventually cause an application to crash. -*Note*: On certain file systems (such as NTFS and HFS+) filenames -will always be encoded as UTF-8. On such file systems, passing -non-UTF-8 encoded Buffers to `fs` functions will not work as expected. +## Threadpool Usage + +Note that all file system APIs except `fs.FSWatcher()` and those that are +explicitly synchronous use libuv's threadpool, which can have surprising and +negative performance implications for some applications, see the +[`UV_THREADPOOL_SIZE`][] documentation for more information. ## Class: fs.FSWatcher -Objects returned from [`fs.watch()`][] are of this type. - -The `listener` callback provided to `fs.watch()` receives the returned FSWatcher's -`change` events. +A successful call to [`fs.watch()`][] method will return a new `fs.FSWatcher` +object. -The object itself emits these events: +All `fs.FSWatcher` objects are [`EventEmitter`][]'s that will emit a `'change'` +event whenever a specific watched file is modified. ### Event: 'change' -* `eventType` {string} The type of fs change +* `eventType` {string} The type of change event that has occurred * `filename` {string|Buffer} The filename that changed (if relevant/available) Emitted when something changes in a watched directory or file. @@ -244,7 +316,7 @@ See more details in [`fs.watch()`][]. The `filename` argument may not be provided depending on operating system support. If `filename` is provided, it will be provided as a `Buffer` if `fs.watch()` is called with its `encoding` option set to `'buffer'`, otherwise -`filename` will be a string. +`filename` will be a UTF-8 string. ```js // Example when handled through fs.watch listener @@ -263,28 +335,32 @@ added: v0.5.8 * `error` {Error} -Emitted when an error occurs. +Emitted when an error occurs while watching the file. ### watcher.close() -Stop watching for changes on the given `fs.FSWatcher`. +Stop watching for changes on the given `fs.FSWatcher`. Once stopped, the +`fs.FSWatcher` object is no longer usable. ## Class: fs.ReadStream -`ReadStream` is a [Readable Stream][]. +A successful call to `fs.createReadStream()` will return a new `fs.ReadStream` +object. + +All `fs.ReadStream` objects are [Readable Streams][]. ### Event: 'close' -Emitted when the `ReadStream`'s underlying file descriptor has been closed. +Emitted when the `fs.ReadStream`'s underlying file descriptor has been closed. ### Event: 'open' -The number of bytes read so far. +* Value: {number} + +The number of bytes that have been read so far. ### readStream.path +* Value: {string|Buffer} + The path to the file the stream is reading from as specified in the first argument to `fs.createReadStream()`. If `path` is passed as a string, then `readStream.path` will be a string. If `path` is passed as a `Buffer`, then @@ -321,20 +401,12 @@ changes: description: Added times as numbers. --> +A `fs.Stats` object provides information about a file. + Objects returned from [`fs.stat()`][], [`fs.lstat()`][] and [`fs.fstat()`][] and their synchronous counterparts are of this type. - - `stats.isFile()` - - `stats.isDirectory()` - - `stats.isBlockDevice()` - - `stats.isCharacterDevice()` - - `stats.isSymbolicLink()` (only valid with [`fs.lstat()`][]) - - `stats.isFIFO()` - - `stats.isSocket()` - -For a regular file [`util.inspect(stats)`][] would return a string very -similar to this: - +For example: ```console Stats { dev: 2114, @@ -357,6 +429,159 @@ Stats { birthtime: Mon, 10 Oct 2011 23:24:11 GMT } ``` +### stats.isBlockDevice() + +* Returns: {boolean} + +Returns `true` if the `fs.Stats` object describes a block device. + +### stats.isCharacterDevice() + +* Returns: {boolean} + +Returns `true` if the `fs.Stats` object describes a character device. + +### stats.isDirectory() + +* Returns: {boolean} + +Returns `true` if the `fs.Stats` object describes a file system directory. + +### stats.isFIFO() + +* Returns: {boolean} + +Returns `true` if the `fs.Stats` object describes a first-in-first-out (FIFO) +pipe. + +### stats.isFile() + +* Returns: {boolean} + +Returns `true` if the `fs.Stats` object describes a regular file. + +### stats.isSocket() + +* Returns: {boolean} + +Returns `true` if the `fs.Stats` object describes a socket. + +### stats.isSymbolicLink() + +* Returns: {boolean} + +Returns `true` if the `fs.Stats` object describes a symbolic link. + +*Note*: This method is only valid when using [`fs.lstat()`][] + +### stats.dev + +* Value: {number} + +The numeric identifier of the device containing the file. + +### stats.ino + +* Value: {number} + +The file system specific "Inode" number for the file. + +### stats.mode + +* Value: {number} + +A bit-field describing the file type and mode. + +### stats.nlink + +* Value: {number} + +The number of hard-links that exist for the file. + +### stats.uid + +* Value: {number} + +The numeric user identifier of the user that owns the file (POSIX). + +### stats.gid + +* Value: {number} + +The numeric group identifier of the group that owns the file (POSIX). + +### stats.rdev + +* Value: {number} + +A numeric device identifier if the file is considered "special". + +### stats.blksize + +* Value: {number} + +The file system block size for i/o operations. + +### stats.blocks + +* Value: {number} + +The number of blocks allocated for this file. + +### stats.atimeMs + +* Value: {number} + +The timestamp indicating the last time this file was accessed expressed in +milliseconds since the POSIX Epoch. + +### stats.mtimeMs + +* Value: {number} + +The timestamp indicating the last time this file was modified expressed in +milliseconds since the POSIX Epoch. + +### stats.ctimeMs + +* Value: {number} + +The timestamp indicating the last time the file status was changed expressed +in milliseconds since the POSIX Epoch. + +### stats.birthtimeMs + +* Value: {number} + +The timestamp indicating the creation time of this file expressed in +milliseconds since the POSIX Epoch. + +### stats.atime + +* Value: {Date} + +The timestamp indicating the last time this file was accessed. + +### stats.mtime + +* Value: {Date} + +The timestamp indicating the last time this file was modified. + +### stats.ctime + +* Value: {Date} + +The timestamp indicating the last time the file status was changed. + +### stats.birthtime + +* Value: {Date} + +The timestamp indicating the creation time of this file. + +### Stat Time Values + *Note*: `atimeMs`, `mtimeMs`, `ctimeMs`, `birthtimeMs` are [numbers][MDN-Number] that hold the corresponding times in milliseconds. Their precision is platform specific. `atime`, `mtime`, `ctime`, and `birthtime` are [`Date`][MDN-Date] @@ -364,9 +589,6 @@ object alternate representations of the various times. The `Date` and number values are not connected. Assigning a new number value, or mutating the `Date` value, will not be reflected in the corresponding alternate representation. - -### Stat Time Values - The times in the stat object have the following semantics: * `atime` "Access Time" - Time when file data last accessed. Changed @@ -457,19 +679,19 @@ Tests a user's permissions for the file or directory specified by `path`. The `mode` argument is an optional integer that specifies the accessibility checks to be performed. The following constants define the possible values of `mode`. It is possible to create a mask consisting of the bitwise OR of two or -more values. +more values (e.g. `fs.constants.W_OK | fs.constants.R_OK`). -- `fs.constants.F_OK` - `path` is visible to the calling process. This is useful +* `fs.constants.F_OK` - `path` is visible to the calling process. This is useful for determining if a file exists, but says nothing about `rwx` permissions. Default if no `mode` is specified. -- `fs.constants.R_OK` - `path` can be read by the calling process. -- `fs.constants.W_OK` - `path` can be written by the calling process. -- `fs.constants.X_OK` - `path` can be executed by the calling process. This has +* `fs.constants.R_OK` - `path` can be read by the calling process. +* `fs.constants.W_OK` - `path` can be written by the calling process. +* `fs.constants.X_OK` - `path` can be executed by the calling process. This has no effect on Windows (will behave like `fs.constants.F_OK`). The final argument, `callback`, is a callback function that is invoked with a possible error argument. If any of the accessibility checks fail, the error -argument will be populated. The following example checks if the file +argument will be an `Error` object. The following example checks if the file `/etc/passwd` can be read and written by the current process. ```js @@ -561,7 +783,7 @@ The "not recommended" examples above check for accessibility and then use the file; the "recommended" examples are better because they use the file directly and handle the error, if any. -In general, check for the accessibility of a file only if the file won’t be +In general, check for the accessibility of a file only if the file will not be used directly, for example when its accessibility is a signal from another process. @@ -577,9 +799,33 @@ changes: * `path` {string|Buffer|URL} * `mode` {integer} **Default:** `fs.constants.F_OK` +* Returns: `undefined` + +Synchronously tests a user's permissions for the file or directory specified by +`path`. The `mode` argument is an optional integer that specifies the +accessibility checks to be performed. The following constants define the +possible values of `mode`. It is possible to create a mask consisting of the +bitwise OR of two or more values (e.g. `fs.constants.W_OK | fs.constants.R_OK`). -Synchronous version of [`fs.access()`][]. This throws if any accessibility -checks fail, and does nothing otherwise. +* `fs.constants.F_OK` - `path` is visible to the calling process. This is useful +for determining if a file exists, but says nothing about `rwx` permissions. +Default if no `mode` is specified. +* `fs.constants.R_OK` - `path` can be read by the calling process. +* `fs.constants.W_OK` - `path` can be written by the calling process. +* `fs.constants.X_OK` - `path` can be executed by the calling process. This has +no effect on Windows (will behave like `fs.constants.F_OK`). + +If any of the accessibility checks fail, an `Error` will be thrown. Otherwise, +the method will return `undefined`. + +```js +try { + fs.accessSync('etc/passwd', fs.constants.R_OK | fs.constants.W_OK); + console.log('can read/write'); +} catch (err) { + console.error('no access!'); +} +``` ## fs.appendFile(file, data[, options], callback) * `exception` {Error} @@ -765,6 +770,12 @@ object, so any HTTP response sent, including response headers and payload, *must* be written directly to the `socket` object. Care must be taken to ensure the response is a properly formatted HTTP response message. +`err` is an instance of `Error` with two extra columns: + ++ `bytesParsed`: the bytes count of request packet that Node.js may have parsed + correctly; ++ `rawPacket`: the raw packet of current request. + ### Event: 'close' Both [Writable][] and [Readable][] streams will store data in an internal -buffer that can be retrieved using `writable._writableState.getBuffer()` or -`readable._readableState.buffer`, respectively. +buffer that can be retrieved using `writable.writableBuffer` or +`readable.readableBuffer`, respectively. The amount of data potentially buffered depends on the `highWaterMark` option passed into the streams constructor. For normal streams, the `highWaterMark` @@ -441,10 +441,18 @@ See also: [`writable.cork()`][]. - Return the value of `highWaterMark` passed when constructing this `Writable`. +##### writable.writableLength + + +This property contains the number of bytes (or objects) in the queue +ready to be written. The value provides introspection data regarding +the status of the `highWaterMark`. + ##### writable.write(chunk[, encoding][, callback]) + +This property contains the number of bytes (or objects) in the queue +ready to be read. The value provides introspection data regarding +the status of the `highWaterMark`. + ##### readable.resume() -The `tty.ReadStream` class is a subclass of `net.Socket` that represents the -readable side of a TTY. In normal circumstances `process.stdin` will be the +The `tty.ReadStream` class is a subclass of [`net.Socket`][] that represents the +readable side of a TTY. In normal circumstances [`process.stdin`][] will be the only `tty.ReadStream` instance in a Node.js process and there should be no reason to create additional instances. @@ -52,7 +53,7 @@ raw device. Defaults to `false`. added: v0.5.8 --> -A `boolean` that is always `true`. +A `boolean` that is always `true` for `tty.ReadStream` instances. ### readStream.setRawMode(mode) The `tty.WriteStream` class is a subclass of `net.Socket` that represents the -writable side of a TTY. In normal circumstances, `process.stdout` and -`process.stderr` will be the only `tty.WriteStream` instances created for a +writable side of a TTY. In normal circumstances, [`process.stdout`][] and +[`process.stderr`][] will be the only `tty.WriteStream` instances created for a Node.js process and there should be no reason to create additional instances. ### Event: 'resize' @@ -130,3 +131,8 @@ added: v0.5.8 The `tty.isatty()` method returns `true` if the given `fd` is associated with a TTY and `false` if it is not, including whenever `fd` is not a non-negative integer. + +[`net.Socket`]: net.html#net_class_net_socket +[`process.stdin`]: process.html#process_process_stdin +[`process.stdout`]: process.html#process_process_stdout +[`process.stderr`]: process.html#process_process_stderr diff --git a/doc/api/util.md b/doc/api/util.md index 3e663e7c326692..95b5b825fde6df 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -21,9 +21,10 @@ added: v8.2.0 * Returns: {Function} a callback style function Takes an `async` function (or a function that returns a Promise) and returns a -function following the Node.js error first callback style. In the callback, the -first argument will be the rejection reason (or `null` if the Promise resolved), -and the second argument will be the resolved value. +function following the error-first callback style, i.e. taking +a `(err, value) => ...` callback as the last argument. In the callback, the +first argument will be the rejection reason (or `null` if the Promise +resolved), and the second argument will be the resolved value. For example: @@ -489,8 +490,8 @@ added: v8.0.0 * `original` {Function} * Returns: {Function} -Takes a function following the common Node.js callback style, i.e. taking a -`(err, value) => ...` callback as the last argument, and returns a version +Takes a function following the common error-first callback style, i.e. taking +a `(err, value) => ...` callback as the last argument, and returns a version that returns promises. For example: @@ -526,9 +527,9 @@ will return its value, see [Custom promisified functions][]. `promisify()` assumes that `original` is a function taking a callback as its final argument in all cases. If `original` is not a function, `promisify()` -will throw an error. If `original` is a function but its last argument is not a -Node.js style callback, it will still be passed a Node.js style callback -as its last argument. +will throw an error. If `original` is a function but its last argument is not +an error-first callback, it will still be passed an error-first +callback as its last argument. ### Custom promisified functions diff --git a/doc/api/v8.md b/doc/api/v8.md index 64c9be1a88b688..c9d2512fddff2f 100644 --- a/doc/api/v8.md +++ b/doc/api/v8.md @@ -269,7 +269,7 @@ by subclasses. This method is called to generate error objects that will be thrown when an object can not be cloned. -This method defaults to the [`Error`][] constructor and can be be overridden on +This method defaults to the [`Error`][] constructor and can be overridden on subclasses. #### serializer.\_getSharedArrayBufferId(sharedArrayBuffer) diff --git a/doc/api/vm.md b/doc/api/vm.md index 609ee6b895c91a..a26ee4ed94d090 100644 --- a/doc/api/vm.md +++ b/doc/api/vm.md @@ -87,9 +87,8 @@ changes: depending on whether code cache data is produced successfully. Creating a new `vm.Script` object compiles `code` but does not run it. The -compiled `vm.Script` can be run later multiple times. It is important to note -that the `code` is not bound to any global object; rather, it is bound before -each run, just for that run. +compiled `vm.Script` can be run later multiple times. The `code` is not bound to +any global object; rather, it is bound before each run, just for that run. ### script.runInContext(contextifiedSandbox[, options]) * `sandbox` {Object} +* `options` {Object} + * `name` {string} Human-readable name of the newly created context. + **Default:** `'VM Context i'`, where `i` is an ascending numerical index of + the created context. + * `origin` {string} [Origin][origin] corresponding to the newly created + context for display purposes. The origin should be formatted like a URL, + but with only the scheme, host, and port (if necessary), like the value of + the [`url.origin`][] property of a [`URL`][] object. Most notably, this + string should omit the trailing slash, as that denotes a path. + **Default:** `''`. If given a `sandbox` object, the `vm.createContext()` method will [prepare that sandbox][contextified] so that it can be used in calls to @@ -282,6 +300,9 @@ web browser, the method can be used to create a single sandbox representing a window's global object, then run all `