diff options
author | Anna Henningsen <anna@addaleax.net> | 2018-08-10 02:45:28 +0200 |
---|---|---|
committer | Anna Henningsen <anna@addaleax.net> | 2018-08-22 23:37:19 +0200 |
commit | 29a71bae40ffa0bbc8ba6b2bdf051a09987da7f7 (patch) | |
tree | 1d66e5b012218ede32c5219d9918d2e2a897ee7b /src/node_options.cc | |
parent | 92880f31da1eca98a42e0f61708b10d9d8d83955 (diff) | |
download | android-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.cc | 219 |
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 |