summaryrefslogtreecommitdiff
path: root/src/node_options.cc
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2018-08-10 02:45:28 +0200
committerAnna Henningsen <anna@addaleax.net>2018-08-22 23:37:19 +0200
commit29a71bae40ffa0bbc8ba6b2bdf051a09987da7f7 (patch)
tree1d66e5b012218ede32c5219d9918d2e2a897ee7b /src/node_options.cc
parent92880f31da1eca98a42e0f61708b10d9d8d83955 (diff)
downloadandroid-node-v8-29a71bae40ffa0bbc8ba6b2bdf051a09987da7f7.tar.gz
android-node-v8-29a71bae40ffa0bbc8ba6b2bdf051a09987da7f7.tar.bz2
android-node-v8-29a71bae40ffa0bbc8ba6b2bdf051a09987da7f7.zip
src: refactor options parsing
This is a major refactor of our Node’s parser. See `node_options.cc` for how it is used, and `node_options-inl.h` for the bulk of its implementation. Unfortunately, the implementation has come to have some complexity, in order to meet the following goals: - Make it easy to *use* for defining or changing options. - Keep it (mostly) backwards-compatible. - No tests were harmed as part of this commit. - Be as consistent as possible. - In particular, options can now generally accept arguments through both `--foo=bar` notation and `--foo bar` notation. We were previously very inconsistent on this point. - Separate into different levels of scope, namely per-process (global), per-Isolate and per-Environment (+ debug options). - Allow programmatic accessibility in the future. - This includes a possible expansion for `--help` output. This commit also leaves a number of `TODO` comments, mostly for improving consistency even more (possibly with having to modify tests), improving embedder support, as well as removing pieces of exposed configuration variables that should never have become part of the public API but unfortunately are at this point. PR-URL: https://github.com/nodejs/node/pull/22392 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Gus Caplan <me@gus.host>
Diffstat (limited to 'src/node_options.cc')
-rw-r--r--src/node_options.cc219
1 files changed, 219 insertions, 0 deletions
diff --git a/src/node_options.cc b/src/node_options.cc
new file mode 100644
index 0000000000..b10de9ef28
--- /dev/null
+++ b/src/node_options.cc
@@ -0,0 +1,219 @@
+#include "node_options-inl.h"
+#include <errno.h>
+
+namespace node {
+
+DebugOptionsParser::DebugOptionsParser() {
+ AddOption("--inspect-port", &DebugOptions::host_port,
+ kAllowedInEnvironment);
+ AddAlias("--debug-port", "--inspect-port");
+
+ AddOption("--inspect", &DebugOptions::inspector_enabled,
+ kAllowedInEnvironment);
+ AddAlias("--inspect=", { "--inspect-port", "--inspect" });
+
+ AddOption("--debug", &DebugOptions::deprecated_debug);
+ AddAlias("--debug=", { "--inspect-port", "--debug" });
+
+ AddOption("--inspect-brk", &DebugOptions::break_first_line,
+ kAllowedInEnvironment);
+ Implies("--inspect-brk", "--inspect");
+ AddAlias("--inspect-brk=", { "--inspect-port", "--inspect-brk" });
+
+ AddOption("--inspect-brk-node", &DebugOptions::break_node_first_line);
+ Implies("--inspect-brk-node", "--inspect");
+ AddAlias("--inspect-brk-node=", { "--inspect-port", "--inspect-brk-node" });
+
+ AddOption("--debug-brk", &DebugOptions::break_first_line);
+ Implies("--debug-brk", "--debug");
+ AddAlias("--debug-brk=", { "--inspect-port", "--debug-brk" });
+}
+
+DebugOptionsParser DebugOptionsParser::instance;
+
+EnvironmentOptionsParser::EnvironmentOptionsParser() {
+ AddOption("--experimental-modules", &EnvironmentOptions::experimental_modules,
+ kAllowedInEnvironment);
+ AddOption("--experimental-repl-await",
+ &EnvironmentOptions::experimental_repl_await,
+ kAllowedInEnvironment);
+ AddOption("--experimental-vm-modules",
+ &EnvironmentOptions::experimental_vm_modules,
+ kAllowedInEnvironment);
+ AddOption("--experimental-worker", &EnvironmentOptions::experimental_worker,
+ kAllowedInEnvironment);
+ AddOption("--expose-internals", &EnvironmentOptions::expose_internals);
+ // TODO(addaleax): Remove this when adding -/_ canonicalization to the parser.
+ AddAlias("--expose_internals", "--expose-internals");
+ AddOption("--loader", &EnvironmentOptions::userland_loader,
+ kAllowedInEnvironment);
+ AddOption("--no-deprecation", &EnvironmentOptions::no_deprecation,
+ kAllowedInEnvironment);
+ AddOption("--no-force-async-hooks-checks",
+ &EnvironmentOptions::no_force_async_hooks_checks,
+ kAllowedInEnvironment);
+ AddOption("--no-warnings", &EnvironmentOptions::no_warnings,
+ kAllowedInEnvironment);
+ AddOption("--pending-deprecation", &EnvironmentOptions::pending_deprecation,
+ kAllowedInEnvironment);
+ AddOption("--preserve-symlinks", &EnvironmentOptions::preserve_symlinks);
+ AddOption("--preserve-symlinks-main",
+ &EnvironmentOptions::preserve_symlinks_main);
+ AddOption("--prof-process", &EnvironmentOptions::prof_process);
+ AddOption("--redirect-warnings", &EnvironmentOptions::redirect_warnings,
+ kAllowedInEnvironment);
+ AddOption("--throw-deprecation", &EnvironmentOptions::throw_deprecation,
+ kAllowedInEnvironment);
+ AddOption("--trace-deprecation", &EnvironmentOptions::trace_deprecation,
+ kAllowedInEnvironment);
+ AddOption("--trace-sync-io", &EnvironmentOptions::trace_sync_io,
+ kAllowedInEnvironment);
+ AddOption("--trace-warnings", &EnvironmentOptions::trace_warnings,
+ kAllowedInEnvironment);
+
+ AddOption("--check", &EnvironmentOptions::syntax_check_only);
+ AddAlias("-c", "--check");
+ // This option is only so that we can tell --eval with an empty string from
+ // no eval at all. Having it not start with a dash makes it inaccessible
+ // from the parser itself, but available for using Implies().
+ // TODO(addaleax): When moving --help over to something generated from the
+ // programmatic descriptions, this will need some special care.
+ // (See also [ssl_openssl_cert_store] below.)
+ AddOption("[has_eval_string]", &EnvironmentOptions::has_eval_string);
+ AddOption("--eval", &EnvironmentOptions::eval_string);
+ Implies("--eval", "[has_eval_string]");
+ AddOption("--print", &EnvironmentOptions::print_eval);
+ AddAlias("-e", "--eval");
+ AddAlias("--print <arg>", "-pe");
+ AddAlias("-pe", { "--print", "--eval" });
+ AddAlias("-p", "--print");
+ AddOption("--require", &EnvironmentOptions::preload_modules,
+ kAllowedInEnvironment);
+ AddAlias("-r", "--require");
+ AddOption("--interactive", &EnvironmentOptions::force_repl);
+ AddAlias("-i", "--interactive");
+
+ AddOption("--napi-modules", NoOp {}, kAllowedInEnvironment);
+
+ Insert(&DebugOptionsParser::instance,
+ &EnvironmentOptions::get_debug_options);
+}
+
+EnvironmentOptionsParser EnvironmentOptionsParser::instance;
+
+PerIsolateOptionsParser::PerIsolateOptionsParser() {
+ AddOption("--track-heap-objects", &PerIsolateOptions::track_heap_objects,
+ kAllowedInEnvironment);
+
+ // Explicitly add some V8 flags to mark them as allowed in NODE_OPTIONS.
+ AddOption("--abort_on_uncaught_exception", V8Option {},
+ kAllowedInEnvironment);
+ AddOption("--max_old_space_size", V8Option {}, kAllowedInEnvironment);
+ AddOption("--perf_basic_prof", V8Option {}, kAllowedInEnvironment);
+ AddOption("--perf_prof", V8Option {}, kAllowedInEnvironment);
+ AddOption("--stack_trace_limit", V8Option {}, kAllowedInEnvironment);
+
+ Insert(&EnvironmentOptionsParser::instance,
+ &PerIsolateOptions::get_per_env_options);
+}
+
+PerIsolateOptionsParser PerIsolateOptionsParser::instance;
+
+PerProcessOptionsParser::PerProcessOptionsParser() {
+ AddOption("--title", &PerProcessOptions::title, kAllowedInEnvironment);
+ AddOption("--trace-event-categories",
+ &PerProcessOptions::trace_event_categories,
+ kAllowedInEnvironment);
+ AddOption("--trace-event-file-pattern",
+ &PerProcessOptions::trace_event_file_pattern,
+ kAllowedInEnvironment);
+ AddAlias("--trace-events-enabled", {
+ "--trace-event-categories", "v8,node,node.async_hooks" });
+ AddOption("--v8-pool-size", &PerProcessOptions::v8_thread_pool_size,
+ kAllowedInEnvironment);
+ AddOption("--zero-fill-buffers", &PerProcessOptions::zero_fill_all_buffers,
+ kAllowedInEnvironment);
+
+ AddOption("--security-reverts", &PerProcessOptions::security_reverts);
+ AddOption("--help", &PerProcessOptions::print_help);
+ AddAlias("-h", "--help");
+ AddOption("--version", &PerProcessOptions::print_version);
+ AddAlias("-v", "--version");
+ AddOption("--v8-options", &PerProcessOptions::print_v8_help);
+
+#ifdef NODE_HAVE_I18N_SUPPORT
+ AddOption("--icu-data-dir", &PerProcessOptions::icu_data_dir,
+ kAllowedInEnvironment);
+#endif
+
+#if HAVE_OPENSSL
+ AddOption("--openssl-config", &PerProcessOptions::openssl_config,
+ kAllowedInEnvironment);
+ AddOption("--tls-cipher-list", &PerProcessOptions::tls_cipher_list,
+ kAllowedInEnvironment);
+ AddOption("--use-openssl-ca", &PerProcessOptions::use_openssl_ca,
+ kAllowedInEnvironment);
+ AddOption("--use-bundled-ca", &PerProcessOptions::use_bundled_ca,
+ kAllowedInEnvironment);
+ // Similar to [has_eval_string] above, except that the separation between
+ // this and use_openssl_ca only exists for option validation after parsing.
+ // This is not ideal.
+ AddOption("[ssl_openssl_cert_store]",
+ &PerProcessOptions::ssl_openssl_cert_store);
+ Implies("--use-openssl-ca", "[ssl_openssl_cert_store]");
+ ImpliesNot("--use-bundled-ca", "[ssl_openssl_cert_store]");
+#if NODE_FIPS_MODE
+ AddOption("--enable-fips", &PerProcessOptions::enable_fips_crypto,
+ kAllowedInEnvironment);
+ AddOption("--force-fips", &PerProcessOptions::force_fips_crypto,
+ kAllowedInEnvironment);
+#endif
+#endif
+
+ Insert(&PerIsolateOptionsParser::instance,
+ &PerProcessOptions::get_per_isolate_options);
+}
+
+PerProcessOptionsParser PerProcessOptionsParser::instance;
+
+inline std::string RemoveBrackets(const std::string& host) {
+ if (!host.empty() && host.front() == '[' && host.back() == ']')
+ return host.substr(1, host.size() - 2);
+ else
+ return host;
+}
+
+inline int ParseAndValidatePort(const std::string& port, std::string* error) {
+ char* endptr;
+ errno = 0;
+ const long result = strtol(port.c_str(), &endptr, 10); // NOLINT(runtime/int)
+ if (errno != 0 || *endptr != '\0'||
+ (result != 0 && result < 1024) || result > 65535) {
+ *error = "Port must be 0 or in range 1024 to 65535.";
+ }
+ return static_cast<int>(result);
+}
+
+HostPort SplitHostPort(const std::string& arg, std::string* error) {
+ // remove_brackets only works if no port is specified
+ // so if it has an effect only an IPv6 address was specified.
+ std::string host = RemoveBrackets(arg);
+ if (host.length() < arg.length())
+ return HostPort { host, -1 };
+
+ size_t colon = arg.rfind(':');
+ if (colon == std::string::npos) {
+ // Either a port number or a host name. Assume that
+ // if it's not all decimal digits, it's a host name.
+ for (char c : arg) {
+ if (c < '0' || c > '9') {
+ return HostPort { arg, -1 };
+ }
+ }
+ return HostPort { "", ParseAndValidatePort(arg, error) };
+ }
+ // Host and port found:
+ return HostPort { RemoveBrackets(arg.substr(0, colon)),
+ ParseAndValidatePort(arg.substr(colon + 1), error) };
+}
+} // namespace node