mirror of
https://github.com/zebrajr/node.git
synced 2026-01-15 12:15:26 +00:00
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>
This commit is contained in:
5
node.gyp
5
node.gyp
@@ -343,7 +343,6 @@
|
||||
'src/node_config.cc',
|
||||
'src/node_constants.cc',
|
||||
'src/node_contextify.cc',
|
||||
'src/node_debug_options.cc',
|
||||
'src/node_domain.cc',
|
||||
'src/node_encoding.cc',
|
||||
'src/node_errors.h',
|
||||
@@ -351,6 +350,7 @@
|
||||
'src/node_http2.cc',
|
||||
'src/node_http_parser.cc',
|
||||
'src/node_messaging.cc',
|
||||
'src/node_options.cc',
|
||||
'src/node_os.cc',
|
||||
'src/node_platform.cc',
|
||||
'src/node_perf.cc',
|
||||
@@ -407,7 +407,6 @@
|
||||
'src/node_code_cache.h',
|
||||
'src/node_constants.h',
|
||||
'src/node_contextify.h',
|
||||
'src/node_debug_options.h',
|
||||
'src/node_file.h',
|
||||
'src/node_http2.h',
|
||||
'src/node_http2_state.h',
|
||||
@@ -415,6 +414,8 @@
|
||||
'src/node_javascript.h',
|
||||
'src/node_messaging.h',
|
||||
'src/node_mutex.h',
|
||||
'src/node_options.h',
|
||||
'src/node_options-inl.h',
|
||||
'src/node_perf.h',
|
||||
'src/node_perf_common.h',
|
||||
'src/node_persistent.h',
|
||||
|
||||
@@ -564,6 +564,14 @@ Environment::file_handle_read_wrap_freelist() {
|
||||
return file_handle_read_wrap_freelist_;
|
||||
}
|
||||
|
||||
inline std::shared_ptr<EnvironmentOptions> Environment::options() {
|
||||
return options_;
|
||||
}
|
||||
|
||||
inline std::shared_ptr<PerIsolateOptions> IsolateData::options() {
|
||||
return options_;
|
||||
}
|
||||
|
||||
void Environment::CreateImmediate(native_immediate_callback cb,
|
||||
void* data,
|
||||
v8::Local<v8::Object> obj,
|
||||
|
||||
26
src/env.cc
26
src/env.cc
@@ -48,6 +48,8 @@ IsolateData::IsolateData(Isolate* isolate,
|
||||
if (platform_ != nullptr)
|
||||
platform_->RegisterIsolate(this, event_loop);
|
||||
|
||||
options_.reset(new PerIsolateOptions(*per_process_opts->per_isolate));
|
||||
|
||||
// Create string and private symbol properties as internalized one byte
|
||||
// strings after the platform is properly initialized.
|
||||
//
|
||||
@@ -136,9 +138,6 @@ Environment::Environment(IsolateData* isolate_data,
|
||||
makecallback_cntr_(0),
|
||||
should_abort_on_uncaught_toggle_(isolate_, 1),
|
||||
trace_category_state_(isolate_, kTraceCategoryCount),
|
||||
#if HAVE_INSPECTOR
|
||||
inspector_agent_(new inspector::Agent(this)),
|
||||
#endif
|
||||
http_parser_buffer_(nullptr),
|
||||
fs_stats_field_array_(isolate_, kFsStatsFieldsLength * 2),
|
||||
fs_stats_field_bigint_array_(isolate_, kFsStatsFieldsLength * 2),
|
||||
@@ -148,6 +147,19 @@ Environment::Environment(IsolateData* isolate_data,
|
||||
v8::Context::Scope context_scope(context);
|
||||
set_as_external(v8::External::New(isolate(), this));
|
||||
|
||||
// We create new copies of the per-Environment option sets, so that it is
|
||||
// easier to modify them after Environment creation. The defaults are
|
||||
// part of the per-Isolate option set, for which in turn the defaults are
|
||||
// part of the per-process option set.
|
||||
options_.reset(new EnvironmentOptions(*isolate_data->options()->per_env));
|
||||
options_->debug_options.reset(new DebugOptions(*options_->debug_options));
|
||||
|
||||
#if HAVE_INSPECTOR
|
||||
// We can only create the inspector agent after having cloned the options.
|
||||
inspector_agent_ =
|
||||
std::unique_ptr<inspector::Agent>(new inspector::Agent(this));
|
||||
#endif
|
||||
|
||||
AssignToContext(context, ContextInfo(""));
|
||||
|
||||
if (tracing_agent_writer_ != nullptr) {
|
||||
@@ -211,10 +223,8 @@ Environment::~Environment() {
|
||||
delete[] http_parser_buffer_;
|
||||
}
|
||||
|
||||
void Environment::Start(int argc,
|
||||
const char* const* argv,
|
||||
int exec_argc,
|
||||
const char* const* exec_argv,
|
||||
void Environment::Start(const std::vector<std::string>& args,
|
||||
const std::vector<std::string>& exec_args,
|
||||
bool start_profiler_idle_notifier) {
|
||||
HandleScope handle_scope(isolate());
|
||||
Context::Scope context_scope(context());
|
||||
@@ -260,7 +270,7 @@ void Environment::Start(int argc,
|
||||
process_template->GetFunction()->NewInstance(context()).ToLocalChecked();
|
||||
set_process_object(process_object);
|
||||
|
||||
SetupProcessObject(this, argc, argv, exec_argc, exec_argv);
|
||||
SetupProcessObject(this, args, exec_args);
|
||||
|
||||
static uv_once_t init_once = UV_ONCE_INIT;
|
||||
uv_once(&init_once, InitThreadLocalOnce);
|
||||
|
||||
13
src/env.h
13
src/env.h
@@ -34,6 +34,7 @@
|
||||
#include "uv.h"
|
||||
#include "v8.h"
|
||||
#include "node.h"
|
||||
#include "node_options.h"
|
||||
#include "node_http2_state.h"
|
||||
|
||||
#include <list>
|
||||
@@ -365,6 +366,7 @@ class IsolateData {
|
||||
inline uv_loop_t* event_loop() const;
|
||||
inline uint32_t* zero_fill_field() const;
|
||||
inline MultiIsolatePlatform* platform() const;
|
||||
inline std::shared_ptr<PerIsolateOptions> options();
|
||||
|
||||
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
|
||||
#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
|
||||
@@ -398,6 +400,7 @@ class IsolateData {
|
||||
uv_loop_t* const event_loop_;
|
||||
uint32_t* const zero_fill_field_;
|
||||
MultiIsolatePlatform* platform_;
|
||||
std::shared_ptr<PerIsolateOptions> options_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(IsolateData);
|
||||
};
|
||||
@@ -582,10 +585,8 @@ class Environment {
|
||||
tracing::AgentWriterHandle* tracing_agent_writer);
|
||||
~Environment();
|
||||
|
||||
void Start(int argc,
|
||||
const char* const* argv,
|
||||
int exec_argc,
|
||||
const char* const* exec_argv,
|
||||
void Start(const std::vector<std::string>& args,
|
||||
const std::vector<std::string>& exec_args,
|
||||
bool start_profiler_idle_notifier);
|
||||
|
||||
typedef void (*HandleCleanupCb)(Environment* env,
|
||||
@@ -882,6 +883,8 @@ class Environment {
|
||||
v8::EmbedderGraph* graph,
|
||||
void* data);
|
||||
|
||||
inline std::shared_ptr<EnvironmentOptions> options();
|
||||
|
||||
private:
|
||||
inline void CreateImmediate(native_immediate_callback cb,
|
||||
void* data,
|
||||
@@ -912,6 +915,8 @@ class Environment {
|
||||
size_t makecallback_cntr_;
|
||||
std::vector<double> destroy_async_id_list_;
|
||||
|
||||
std::shared_ptr<EnvironmentOptions> options_;
|
||||
|
||||
AliasedBuffer<uint32_t, v8::Uint32Array> should_abort_on_uncaught_toggle_;
|
||||
int should_not_abort_scope_counter_ = 0;
|
||||
|
||||
|
||||
@@ -608,11 +608,14 @@ class NodeInspectorClient : public V8InspectorClient {
|
||||
std::unique_ptr<MainThreadInterface> interface_;
|
||||
};
|
||||
|
||||
Agent::Agent(Environment* env) : parent_env_(env) {}
|
||||
Agent::Agent(Environment* env)
|
||||
: parent_env_(env),
|
||||
debug_options_(env->options()->debug_options) {}
|
||||
|
||||
Agent::~Agent() = default;
|
||||
|
||||
bool Agent::Start(const std::string& path, const DebugOptions& options) {
|
||||
bool Agent::Start(const std::string& path,
|
||||
std::shared_ptr<DebugOptions> options) {
|
||||
path_ = path;
|
||||
debug_options_ = options;
|
||||
client_ = std::make_shared<NodeInspectorClient>(parent_env_);
|
||||
@@ -626,8 +629,8 @@ bool Agent::Start(const std::string& path, const DebugOptions& options) {
|
||||
StartDebugSignalHandler();
|
||||
}
|
||||
|
||||
bool wait_for_connect = options.wait_for_connect();
|
||||
if (!options.inspector_enabled() || !StartIoThread()) {
|
||||
bool wait_for_connect = options->wait_for_connect();
|
||||
if (!options->inspector_enabled || !StartIoThread()) {
|
||||
return false;
|
||||
}
|
||||
if (wait_for_connect) {
|
||||
@@ -789,7 +792,7 @@ void Agent::ContextCreated(Local<Context> context, const ContextInfo& info) {
|
||||
}
|
||||
|
||||
bool Agent::WillWaitForConnect() {
|
||||
return debug_options_.wait_for_connect();
|
||||
return debug_options_->wait_for_connect();
|
||||
}
|
||||
|
||||
bool Agent::IsActive() {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#error("This header can only be used when inspector is enabled")
|
||||
#endif
|
||||
|
||||
#include "node_debug_options.h"
|
||||
#include "node_options.h"
|
||||
#include "node_persistent.h"
|
||||
#include "v8.h"
|
||||
|
||||
@@ -45,7 +45,7 @@ class Agent {
|
||||
~Agent();
|
||||
|
||||
// Create client_, may create io_ if option enabled
|
||||
bool Start(const std::string& path, const DebugOptions& options);
|
||||
bool Start(const std::string& path, std::shared_ptr<DebugOptions> options);
|
||||
// Stop and destroy io_
|
||||
void Stop();
|
||||
|
||||
@@ -96,7 +96,7 @@ class Agent {
|
||||
// Calls StartIoThread() from off the main thread.
|
||||
void RequestIoThreadStart();
|
||||
|
||||
DebugOptions& options() { return debug_options_; }
|
||||
std::shared_ptr<DebugOptions> options() { return debug_options_; }
|
||||
void ContextCreated(v8::Local<v8::Context> context, const ContextInfo& info);
|
||||
|
||||
private:
|
||||
@@ -109,7 +109,7 @@ class Agent {
|
||||
// Interface for transports, e.g. WebSocket server
|
||||
std::unique_ptr<InspectorIo> io_;
|
||||
std::string path_;
|
||||
DebugOptions debug_options_;
|
||||
std::shared_ptr<DebugOptions> debug_options_;
|
||||
|
||||
bool pending_enable_async_hook_ = false;
|
||||
bool pending_disable_async_hook_ = false;
|
||||
|
||||
@@ -242,7 +242,7 @@ class InspectorIoDelegate: public node::inspector::SocketServerDelegate {
|
||||
std::unique_ptr<InspectorIo> InspectorIo::Start(
|
||||
std::shared_ptr<MainThreadHandle> main_thread,
|
||||
const std::string& path,
|
||||
const DebugOptions& options) {
|
||||
std::shared_ptr<DebugOptions> options) {
|
||||
auto io = std::unique_ptr<InspectorIo>(
|
||||
new InspectorIo(main_thread, path, options));
|
||||
if (io->request_queue_->Expired()) { // Thread is not running
|
||||
@@ -253,7 +253,7 @@ std::unique_ptr<InspectorIo> InspectorIo::Start(
|
||||
|
||||
InspectorIo::InspectorIo(std::shared_ptr<MainThreadHandle> main_thread,
|
||||
const std::string& path,
|
||||
const DebugOptions& options)
|
||||
std::shared_ptr<DebugOptions> options)
|
||||
: main_thread_(main_thread), options_(options),
|
||||
thread_(), script_name_(path), id_(GenerateID()) {
|
||||
Mutex::ScopedLock scoped_lock(thread_start_lock_);
|
||||
@@ -288,7 +288,8 @@ void InspectorIo::ThreadMain() {
|
||||
new InspectorIoDelegate(queue, main_thread_, id_,
|
||||
script_path, script_name_));
|
||||
InspectorSocketServer server(std::move(delegate), &loop,
|
||||
options_.host_name(), options_.port());
|
||||
options_->host().c_str(),
|
||||
options_->port());
|
||||
request_queue_ = queue->handle();
|
||||
// Its lifetime is now that of the server delegate
|
||||
queue.reset();
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#define SRC_INSPECTOR_IO_H_
|
||||
|
||||
#include "inspector_socket_server.h"
|
||||
#include "node_debug_options.h"
|
||||
#include "node_mutex.h"
|
||||
#include "uv.h"
|
||||
|
||||
@@ -46,19 +45,20 @@ class InspectorIo {
|
||||
// Returns empty pointer if thread was not started
|
||||
static std::unique_ptr<InspectorIo> Start(
|
||||
std::shared_ptr<MainThreadHandle> main_thread, const std::string& path,
|
||||
const DebugOptions& options);
|
||||
std::shared_ptr<DebugOptions> options);
|
||||
|
||||
// Will block till the transport thread shuts down
|
||||
~InspectorIo();
|
||||
|
||||
void StopAcceptingNewConnections();
|
||||
std::string host() const { return options_.host_name(); }
|
||||
const std::string& host() const { return options_->host(); }
|
||||
int port() const { return port_; }
|
||||
std::vector<std::string> GetTargetIds() const;
|
||||
|
||||
private:
|
||||
InspectorIo(std::shared_ptr<MainThreadHandle> handle,
|
||||
const std::string& path, const DebugOptions& options);
|
||||
const std::string& path,
|
||||
std::shared_ptr<DebugOptions> options);
|
||||
|
||||
// Wrapper for agent->ThreadMain()
|
||||
static void ThreadMain(void* agent);
|
||||
@@ -72,7 +72,7 @@ class InspectorIo {
|
||||
// Used to post on a frontend interface thread, lives while the server is
|
||||
// running
|
||||
std::shared_ptr<RequestQueue> request_queue_;
|
||||
const DebugOptions options_;
|
||||
std::shared_ptr<DebugOptions> options_;
|
||||
|
||||
// The IO thread runs its own uv_loop to implement the TCP server off
|
||||
// the main thread.
|
||||
|
||||
@@ -242,12 +242,12 @@ void Open(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
if (args.Length() > 0 && args[0]->IsUint32()) {
|
||||
uint32_t port = args[0]->Uint32Value();
|
||||
agent->options().set_port(static_cast<int>(port));
|
||||
agent->options()->host_port.port = port;
|
||||
}
|
||||
|
||||
if (args.Length() > 1 && args[1]->IsString()) {
|
||||
Utf8Value host(env->isolate(), args[1].As<String>());
|
||||
agent->options().set_host_name(*host);
|
||||
agent->options()->host_port.host_name = *host;
|
||||
}
|
||||
|
||||
if (args.Length() > 2 && args[2]->IsBoolean()) {
|
||||
|
||||
816
src/node.cc
816
src/node.cc
File diff suppressed because it is too large
Load Diff
@@ -199,6 +199,8 @@ typedef intptr_t ssize_t;
|
||||
|
||||
namespace node {
|
||||
|
||||
// TODO(addaleax): Deprecate and remove all of these ASAP. They have been
|
||||
// made effectively non-functional anyway.
|
||||
NODE_EXTERN extern bool no_deprecation;
|
||||
#if HAVE_OPENSSL
|
||||
NODE_EXTERN extern bool ssl_openssl_cert_store;
|
||||
@@ -208,7 +210,12 @@ NODE_EXTERN extern bool force_fips_crypto;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// TODO(addaleax): Officially deprecate this and replace it with something
|
||||
// better suited for a public embedder API.
|
||||
NODE_EXTERN int Start(int argc, char* argv[]);
|
||||
|
||||
// TODO(addaleax): Officially deprecate this and replace it with something
|
||||
// better suited for a public embedder API.
|
||||
NODE_EXTERN void Init(int* argc,
|
||||
const char** argv,
|
||||
int* exec_argc,
|
||||
@@ -265,6 +272,8 @@ NODE_EXTERN IsolateData* CreateIsolateData(
|
||||
ArrayBufferAllocator* allocator);
|
||||
NODE_EXTERN void FreeIsolateData(IsolateData* isolate_data);
|
||||
|
||||
// TODO(addaleax): Add an official variant using STL containers, and move
|
||||
// per-Environment options parsing here.
|
||||
NODE_EXTERN Environment* CreateEnvironment(IsolateData* isolate_data,
|
||||
v8::Local<v8::Context> context,
|
||||
int argc,
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
namespace node {
|
||||
|
||||
// TODO(addaleax): Deprecate and remove this ASAP.
|
||||
extern bool zero_fill_all_buffers;
|
||||
|
||||
namespace Buffer {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "node_i18n.h"
|
||||
#include "env-inl.h"
|
||||
#include "util-inl.h"
|
||||
#include "node_debug_options.h"
|
||||
|
||||
namespace node {
|
||||
|
||||
@@ -56,6 +55,7 @@ static void Initialize(Local<Object> target,
|
||||
|
||||
#ifdef NODE_FIPS_MODE
|
||||
READONLY_BOOLEAN_PROPERTY("fipsMode");
|
||||
// TODO(addaleax): Use options parser variable instead.
|
||||
if (force_fips_crypto)
|
||||
READONLY_BOOLEAN_PROPERTY("fipsForced");
|
||||
#endif
|
||||
@@ -72,35 +72,38 @@ static void Initialize(Local<Object> target,
|
||||
READONLY_BOOLEAN_PROPERTY("hasTracing");
|
||||
#endif
|
||||
|
||||
READONLY_STRING_PROPERTY(target, "icuDataDir", icu_data_dir);
|
||||
// TODO(addaleax): This seems to be an unused, private API. Remove it?
|
||||
READONLY_STRING_PROPERTY(target, "icuDataDir",
|
||||
per_process_opts->icu_data_dir);
|
||||
|
||||
#endif // NODE_HAVE_I18N_SUPPORT
|
||||
|
||||
if (config_preserve_symlinks)
|
||||
if (env->options()->preserve_symlinks)
|
||||
READONLY_BOOLEAN_PROPERTY("preserveSymlinks");
|
||||
if (config_preserve_symlinks_main)
|
||||
if (env->options()->preserve_symlinks_main)
|
||||
READONLY_BOOLEAN_PROPERTY("preserveSymlinksMain");
|
||||
|
||||
if (config_experimental_modules) {
|
||||
if (env->options()->experimental_modules) {
|
||||
READONLY_BOOLEAN_PROPERTY("experimentalModules");
|
||||
if (!config_userland_loader.empty()) {
|
||||
READONLY_STRING_PROPERTY(target, "userLoader", config_userland_loader);
|
||||
const std::string& userland_loader = env->options()->userland_loader;
|
||||
if (!userland_loader.empty()) {
|
||||
READONLY_STRING_PROPERTY(target, "userLoader", userland_loader);
|
||||
}
|
||||
}
|
||||
|
||||
if (config_experimental_vm_modules)
|
||||
if (env->options()->experimental_vm_modules)
|
||||
READONLY_BOOLEAN_PROPERTY("experimentalVMModules");
|
||||
|
||||
if (config_experimental_worker)
|
||||
if (env->options()->experimental_worker)
|
||||
READONLY_BOOLEAN_PROPERTY("experimentalWorker");
|
||||
|
||||
if (config_experimental_repl_await)
|
||||
if (env->options()->experimental_repl_await)
|
||||
READONLY_BOOLEAN_PROPERTY("experimentalREPLAwait");
|
||||
|
||||
if (config_pending_deprecation)
|
||||
if (env->options()->pending_deprecation)
|
||||
READONLY_BOOLEAN_PROPERTY("pendingDeprecation");
|
||||
|
||||
if (config_expose_internals)
|
||||
if (env->options()->expose_internals)
|
||||
READONLY_BOOLEAN_PROPERTY("exposeInternals");
|
||||
|
||||
if (env->abort_on_uncaught_exception())
|
||||
@@ -110,22 +113,25 @@ static void Initialize(Local<Object> target,
|
||||
"bits",
|
||||
Number::New(env->isolate(), 8 * sizeof(intptr_t)));
|
||||
|
||||
if (!config_warning_file.empty()) {
|
||||
READONLY_STRING_PROPERTY(target, "warningFile", config_warning_file);
|
||||
const std::string& warning_file = env->options()->redirect_warnings;
|
||||
if (!warning_file.empty()) {
|
||||
READONLY_STRING_PROPERTY(target, "warningFile", warning_file);
|
||||
}
|
||||
|
||||
Local<Object> debugOptions = Object::New(isolate);
|
||||
READONLY_PROPERTY(target, "debugOptions", debugOptions);
|
||||
std::shared_ptr<DebugOptions> debug_options = env->options()->debug_options;
|
||||
Local<Object> debug_options_obj = Object::New(isolate);
|
||||
READONLY_PROPERTY(target, "debugOptions", debug_options_obj);
|
||||
|
||||
READONLY_STRING_PROPERTY(debugOptions, "host", debug_options.host_name());
|
||||
READONLY_STRING_PROPERTY(debug_options_obj, "host",
|
||||
debug_options->host());
|
||||
|
||||
READONLY_PROPERTY(debugOptions,
|
||||
READONLY_PROPERTY(debug_options_obj,
|
||||
"port",
|
||||
Integer::New(isolate, debug_options.port()));
|
||||
Integer::New(isolate, debug_options->port()));
|
||||
|
||||
READONLY_PROPERTY(debugOptions,
|
||||
READONLY_PROPERTY(debug_options_obj,
|
||||
"inspectorEnabled",
|
||||
Boolean::New(isolate, debug_options.inspector_enabled()));
|
||||
Boolean::New(isolate, debug_options->inspector_enabled));
|
||||
} // InitConfig
|
||||
|
||||
} // namespace node
|
||||
|
||||
@@ -51,10 +51,6 @@ namespace node {
|
||||
using v8::Local;
|
||||
using v8::Object;
|
||||
|
||||
#if HAVE_OPENSSL
|
||||
const char* default_cipher_list = DEFAULT_CIPHER_LIST_CORE;
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
void DefineErrnoConstants(Local<Object> target) {
|
||||
@@ -1240,7 +1236,7 @@ void DefineCryptoConstants(Local<Object> target) {
|
||||
DEFAULT_CIPHER_LIST_CORE);
|
||||
NODE_DEFINE_STRING_CONSTANT(target,
|
||||
"defaultCipherList",
|
||||
default_cipher_list);
|
||||
per_process_opts->tls_cipher_list.c_str());
|
||||
#endif
|
||||
NODE_DEFINE_CONSTANT(target, INT_MAX);
|
||||
}
|
||||
|
||||
@@ -66,10 +66,6 @@
|
||||
|
||||
namespace node {
|
||||
|
||||
#if HAVE_OPENSSL
|
||||
extern const char* default_cipher_list;
|
||||
#endif
|
||||
|
||||
void DefineConstants(v8::Isolate* isolate, v8::Local<v8::Object> target);
|
||||
} // namespace node
|
||||
|
||||
|
||||
@@ -756,6 +756,8 @@ static X509_STORE* NewRootCertStore() {
|
||||
if (*system_cert_path != '\0') {
|
||||
X509_STORE_load_locations(store, system_cert_path, nullptr);
|
||||
}
|
||||
// TODO(addaleax): Replace `ssl_openssl_cert_store` with
|
||||
// `per_process_opts->ssl_openssl_cert_store`.
|
||||
if (ssl_openssl_cert_store) {
|
||||
X509_STORE_set_default_paths(store);
|
||||
} else {
|
||||
@@ -5094,14 +5096,14 @@ void InitCryptoOnce() {
|
||||
OPENSSL_no_config();
|
||||
|
||||
// --openssl-config=...
|
||||
if (!openssl_config.empty()) {
|
||||
if (!per_process_opts->openssl_config.empty()) {
|
||||
OPENSSL_load_builtin_modules();
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
ENGINE_load_builtin_engines();
|
||||
#endif
|
||||
ERR_clear_error();
|
||||
CONF_modules_load_file(
|
||||
openssl_config.c_str(),
|
||||
per_process_opts->openssl_config.c_str(),
|
||||
nullptr,
|
||||
CONF_MFLAGS_DEFAULT_SECTION);
|
||||
int err = ERR_get_error();
|
||||
@@ -5119,6 +5121,9 @@ void InitCryptoOnce() {
|
||||
#ifdef NODE_FIPS_MODE
|
||||
/* Override FIPS settings in cnf file, if needed. */
|
||||
unsigned long err = 0; // NOLINT(runtime/int)
|
||||
// TODO(addaleax): Use commented part instead.
|
||||
/*if (per_process_opts->enable_fips_crypto ||
|
||||
per_process_opts->force_fips_crypto) {*/
|
||||
if (enable_fips_crypto || force_fips_crypto) {
|
||||
if (0 == FIPS_mode() && !FIPS_mode_set(1)) {
|
||||
err = ERR_get_error();
|
||||
@@ -5181,6 +5186,7 @@ void GetFipsCrypto(const FunctionCallbackInfo<Value>& args) {
|
||||
}
|
||||
|
||||
void SetFipsCrypto(const FunctionCallbackInfo<Value>& args) {
|
||||
// TODO(addaleax): Use options parser variables instead.
|
||||
CHECK(!force_fips_crypto);
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
const bool enabled = FIPS_mode();
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
#include "node_debug_options.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "util.h"
|
||||
|
||||
namespace node {
|
||||
|
||||
namespace {
|
||||
const int default_inspector_port = 9229;
|
||||
|
||||
inline std::string remove_brackets(const std::string& host) {
|
||||
if (!host.empty() && host.front() == '[' && host.back() == ']')
|
||||
return host.substr(1, host.size() - 2);
|
||||
else
|
||||
return host;
|
||||
}
|
||||
|
||||
int parse_and_validate_port(const std::string& port) {
|
||||
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) {
|
||||
fprintf(stderr, "Debug port must be 0 or in range 1024 to 65535.\n");
|
||||
exit(12);
|
||||
}
|
||||
return static_cast<int>(result);
|
||||
}
|
||||
|
||||
std::pair<std::string, int> split_host_port(const std::string& arg) {
|
||||
// remove_brackets only works if no port is specified
|
||||
// so if it has an effect only an IPv6 address was specified
|
||||
std::string host = remove_brackets(arg);
|
||||
if (host.length() < arg.length())
|
||||
return {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 {arg, -1};
|
||||
}
|
||||
}
|
||||
return {"", parse_and_validate_port(arg)};
|
||||
}
|
||||
// host and port found
|
||||
return std::make_pair(remove_brackets(arg.substr(0, colon)),
|
||||
parse_and_validate_port(arg.substr(colon + 1)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DebugOptions::DebugOptions() :
|
||||
inspector_enabled_(false),
|
||||
deprecated_debug_(false),
|
||||
break_first_line_(false),
|
||||
break_node_first_line_(false),
|
||||
host_name_("127.0.0.1"), port_(-1) { }
|
||||
|
||||
bool DebugOptions::ParseOption(const char* argv0, const std::string& option) {
|
||||
bool has_argument = false;
|
||||
std::string option_name;
|
||||
std::string argument;
|
||||
|
||||
auto pos = option.find("=");
|
||||
if (pos == std::string::npos) {
|
||||
option_name = option;
|
||||
} else {
|
||||
option_name = option.substr(0, pos);
|
||||
argument = option.substr(pos + 1);
|
||||
|
||||
if (argument.length() > 0)
|
||||
has_argument = true;
|
||||
else
|
||||
argument.clear();
|
||||
}
|
||||
|
||||
// Note that --debug-port and --debug-brk in conjunction with --inspect
|
||||
// work but are undocumented.
|
||||
// --debug is no longer valid.
|
||||
// Ref: https://github.com/nodejs/node/issues/12630
|
||||
// Ref: https://github.com/nodejs/node/pull/12949
|
||||
if (option_name == "--inspect") {
|
||||
inspector_enabled_ = true;
|
||||
} else if (option_name == "--debug") {
|
||||
deprecated_debug_ = true;
|
||||
} else if (option_name == "--inspect-brk") {
|
||||
inspector_enabled_ = true;
|
||||
break_first_line_ = true;
|
||||
} else if (option_name == "--inspect-brk-node") {
|
||||
inspector_enabled_ = true;
|
||||
break_node_first_line_ = true;
|
||||
} else if (option_name == "--debug-brk") {
|
||||
break_first_line_ = true;
|
||||
deprecated_debug_ = true;
|
||||
} else if (option_name == "--debug-port" ||
|
||||
option_name == "--inspect-port") {
|
||||
if (!has_argument) {
|
||||
fprintf(stderr, "%s: %s requires an argument\n",
|
||||
argv0, option.c_str());
|
||||
exit(9);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !HAVE_INSPECTOR
|
||||
if (inspector_enabled_) {
|
||||
fprintf(stderr,
|
||||
"Inspector support is not available with this Node.js build\n");
|
||||
}
|
||||
inspector_enabled_ = false;
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// argument can be specified for *any* option to specify host:port
|
||||
if (has_argument) {
|
||||
std::pair<std::string, int> host_port = split_host_port(argument);
|
||||
if (!host_port.first.empty()) {
|
||||
host_name_ = host_port.first;
|
||||
}
|
||||
if (host_port.second >= 0) {
|
||||
port_ = host_port.second;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int DebugOptions::port() const {
|
||||
int port = port_;
|
||||
if (port < 0) {
|
||||
port = default_inspector_port;
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
} // namespace node
|
||||
@@ -1,42 +0,0 @@
|
||||
#ifndef SRC_NODE_DEBUG_OPTIONS_H_
|
||||
#define SRC_NODE_DEBUG_OPTIONS_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
// Forward declaration to break recursive dependency chain with src/env.h.
|
||||
namespace node {
|
||||
|
||||
class DebugOptions {
|
||||
public:
|
||||
DebugOptions();
|
||||
bool ParseOption(const char* argv0, const std::string& option);
|
||||
bool inspector_enabled() const { return inspector_enabled_; }
|
||||
bool deprecated_invocation() const {
|
||||
return deprecated_debug_ &&
|
||||
inspector_enabled_ &&
|
||||
break_first_line_;
|
||||
}
|
||||
bool invalid_invocation() const {
|
||||
return deprecated_debug_ && !inspector_enabled_;
|
||||
}
|
||||
bool wait_for_connect() const {
|
||||
return break_first_line_ || break_node_first_line_;
|
||||
}
|
||||
std::string host_name() const { return host_name_; }
|
||||
void set_host_name(std::string host_name) { host_name_ = host_name; }
|
||||
int port() const;
|
||||
void set_port(int port) { port_ = port; }
|
||||
bool break_node_first_line() const { return break_node_first_line_; }
|
||||
|
||||
private:
|
||||
bool inspector_enabled_;
|
||||
bool deprecated_debug_;
|
||||
bool break_first_line_;
|
||||
bool break_node_first_line_;
|
||||
std::string host_name_;
|
||||
int port_;
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
||||
#endif // SRC_NODE_DEBUG_OPTIONS_H_
|
||||
@@ -31,8 +31,6 @@
|
||||
|
||||
namespace node {
|
||||
|
||||
extern std::string icu_data_dir; // NOLINT(runtime/string)
|
||||
|
||||
namespace i18n {
|
||||
|
||||
bool InitializeICUDirectory(const std::string& path);
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "v8.h"
|
||||
#include "tracing/trace_event.h"
|
||||
#include "node_perf_common.h"
|
||||
#include "node_debug_options.h"
|
||||
#include "node_api.h"
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -171,67 +170,10 @@ struct sockaddr;
|
||||
|
||||
namespace node {
|
||||
|
||||
// Set in node.cc by ParseArgs with the value of --openssl-config.
|
||||
// Used in node_crypto.cc when initializing OpenSSL.
|
||||
extern std::string openssl_config;
|
||||
|
||||
// Set in node.cc by ParseArgs when --preserve-symlinks is used.
|
||||
// Used in node_config.cc to set a constant on process.binding('config')
|
||||
// that is used by lib/module.js
|
||||
extern bool config_preserve_symlinks;
|
||||
|
||||
// Set in node.cc by ParseArgs when --preserve-symlinks-main is used.
|
||||
// Used in node_config.cc to set a constant on process.binding('config')
|
||||
// that is used by lib/module.js
|
||||
extern bool config_preserve_symlinks_main;
|
||||
|
||||
// Set in node.cc by ParseArgs when --experimental-modules is used.
|
||||
// Used in node_config.cc to set a constant on process.binding('config')
|
||||
// that is used by lib/module.js
|
||||
extern bool config_experimental_modules;
|
||||
|
||||
// Set in node.cc by ParseArgs when --experimental-vm-modules is used.
|
||||
// Used in node_config.cc to set a constant on process.binding('config')
|
||||
// that is used by lib/vm.js
|
||||
extern bool config_experimental_vm_modules;
|
||||
|
||||
// Set in node.cc by ParseArgs when --experimental-worker is used.
|
||||
// Used in node_config.cc to set a constant on process.binding('config')
|
||||
// that is used by the module loader.
|
||||
extern bool config_experimental_worker;
|
||||
|
||||
// Set in node.cc by ParseArgs when --experimental-repl-await is used.
|
||||
// Used in node_config.cc to set a constant on process.binding('config')
|
||||
// that is used by lib/repl.js.
|
||||
extern bool config_experimental_repl_await;
|
||||
|
||||
// Set in node.cc by ParseArgs when --loader is used.
|
||||
// Used in node_config.cc to set a constant on process.binding('config')
|
||||
// that is used by lib/internal/bootstrap/node.js
|
||||
extern std::string config_userland_loader;
|
||||
|
||||
// Set in node.cc by ParseArgs when --expose-internals or --expose_internals is
|
||||
// used.
|
||||
// Used in node_config.cc to set a constant on process.binding('config')
|
||||
// that is used by lib/internal/bootstrap/node.js
|
||||
extern bool config_expose_internals;
|
||||
|
||||
// Set in node.cc by ParseArgs when --redirect-warnings= is used.
|
||||
// Used to redirect warning output to a file rather than sending
|
||||
// it to stderr.
|
||||
extern std::string config_warning_file; // NOLINT(runtime/string)
|
||||
|
||||
// Set in node.cc by ParseArgs when --pending-deprecation or
|
||||
// NODE_PENDING_DEPRECATION is used
|
||||
extern bool config_pending_deprecation;
|
||||
|
||||
// Tells whether it is safe to call v8::Isolate::GetCurrent().
|
||||
extern bool v8_initialized;
|
||||
|
||||
// Contains initial debug options.
|
||||
// Set in node.cc.
|
||||
// Used in node_config.cc.
|
||||
extern node::DebugOptions debug_options;
|
||||
extern std::shared_ptr<PerProcessOptions> per_process_opts;
|
||||
|
||||
// Forward declaration
|
||||
class Environment;
|
||||
@@ -415,10 +357,8 @@ inline v8::Local<v8::Value> FillGlobalStatsArray(Environment* env,
|
||||
void SetupBootstrapObject(Environment* env,
|
||||
v8::Local<v8::Object> bootstrapper);
|
||||
void SetupProcessObject(Environment* env,
|
||||
int argc,
|
||||
const char* const* argv,
|
||||
int exec_argc,
|
||||
const char* const* exec_argv);
|
||||
const std::vector<std::string>& args,
|
||||
const std::vector<std::string>& exec_args);
|
||||
|
||||
// Call _register<module_name> functions for all of
|
||||
// the built-in modules. Because built-in modules don't
|
||||
|
||||
422
src/node_options-inl.h
Normal file
422
src/node_options-inl.h
Normal file
@@ -0,0 +1,422 @@
|
||||
#ifndef SRC_NODE_OPTIONS_INL_H_
|
||||
#define SRC_NODE_OPTIONS_INL_H_
|
||||
|
||||
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#include "node_options.h"
|
||||
#include "util.h"
|
||||
#include <cstdlib>
|
||||
|
||||
namespace node {
|
||||
|
||||
PerIsolateOptions* PerProcessOptions::get_per_isolate_options() {
|
||||
return per_isolate.get();
|
||||
}
|
||||
|
||||
DebugOptions* EnvironmentOptions::get_debug_options() {
|
||||
return debug_options.get();
|
||||
}
|
||||
|
||||
EnvironmentOptions* PerIsolateOptions::get_per_env_options() {
|
||||
return per_env.get();
|
||||
}
|
||||
|
||||
template <typename Options>
|
||||
void OptionsParser<Options>::AddOption(const std::string& name,
|
||||
bool Options::* field,
|
||||
OptionEnvvarSettings env_setting) {
|
||||
options_.emplace(name, OptionInfo {
|
||||
kBoolean,
|
||||
std::make_shared<SimpleOptionField<bool>>(field),
|
||||
env_setting
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Options>
|
||||
void OptionsParser<Options>::AddOption(const std::string& name,
|
||||
int64_t Options::* field,
|
||||
OptionEnvvarSettings env_setting) {
|
||||
options_.emplace(name, OptionInfo {
|
||||
kInteger,
|
||||
std::make_shared<SimpleOptionField<int64_t>>(field),
|
||||
env_setting
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Options>
|
||||
void OptionsParser<Options>::AddOption(const std::string& name,
|
||||
std::string Options::* field,
|
||||
OptionEnvvarSettings env_setting) {
|
||||
options_.emplace(name, OptionInfo {
|
||||
kString,
|
||||
std::make_shared<SimpleOptionField<std::string>>(field),
|
||||
env_setting
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Options>
|
||||
void OptionsParser<Options>::AddOption(
|
||||
const std::string& name,
|
||||
std::vector<std::string> Options::* field,
|
||||
OptionEnvvarSettings env_setting) {
|
||||
options_.emplace(name, OptionInfo {
|
||||
kStringList,
|
||||
std::make_shared<SimpleOptionField<std::vector<std::string>>>(field),
|
||||
env_setting
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Options>
|
||||
void OptionsParser<Options>::AddOption(const std::string& name,
|
||||
HostPort Options::* field,
|
||||
OptionEnvvarSettings env_setting) {
|
||||
options_.emplace(name, OptionInfo {
|
||||
kHostPort,
|
||||
std::make_shared<SimpleOptionField<HostPort>>(field),
|
||||
env_setting
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Options>
|
||||
void OptionsParser<Options>::AddOption(const std::string& name, NoOp no_op_tag,
|
||||
OptionEnvvarSettings env_setting) {
|
||||
options_.emplace(name, OptionInfo { kNoOp, nullptr, env_setting });
|
||||
}
|
||||
|
||||
template <typename Options>
|
||||
void OptionsParser<Options>::AddOption(const std::string& name,
|
||||
V8Option v8_option_tag,
|
||||
OptionEnvvarSettings env_setting) {
|
||||
options_.emplace(name, OptionInfo { kV8Option, nullptr, env_setting });
|
||||
}
|
||||
|
||||
template <typename Options>
|
||||
void OptionsParser<Options>::AddAlias(const std::string& from,
|
||||
const std::string& to) {
|
||||
aliases_[from] = { to };
|
||||
}
|
||||
|
||||
template <typename Options>
|
||||
void OptionsParser<Options>::AddAlias(const std::string& from,
|
||||
const std::vector<std::string>& to) {
|
||||
aliases_[from] = to;
|
||||
}
|
||||
|
||||
template <typename Options>
|
||||
void OptionsParser<Options>::AddAlias(
|
||||
const std::string& from,
|
||||
const std::initializer_list<std::string>& to) {
|
||||
AddAlias(from, std::vector<std::string>(to));
|
||||
}
|
||||
|
||||
template <typename Options>
|
||||
void OptionsParser<Options>::Implies(const std::string& from,
|
||||
const std::string& to) {
|
||||
auto it = options_.find(to);
|
||||
CHECK_NE(it, options_.end());
|
||||
CHECK_EQ(it->second.type, kBoolean);
|
||||
implications_.emplace(from, Implication {
|
||||
std::static_pointer_cast<OptionField<bool>>(it->second.field), true
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Options>
|
||||
void OptionsParser<Options>::ImpliesNot(const std::string& from,
|
||||
const std::string& to) {
|
||||
auto it = options_.find(to);
|
||||
CHECK_NE(it, options_.end());
|
||||
CHECK_EQ(it->second.type, kBoolean);
|
||||
implications_.emplace(from, Implication {
|
||||
std::static_pointer_cast<OptionField<bool>>(it->second.field), false
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Options>
|
||||
template <typename OriginalField, typename ChildOptions>
|
||||
auto OptionsParser<Options>::Convert(
|
||||
std::shared_ptr<OriginalField> original,
|
||||
ChildOptions* (Options::* get_child)()) {
|
||||
// If we have a field on ChildOptions, and we want to access it from an
|
||||
// Options instance, we call get_child() on the original Options and then
|
||||
// access it, i.e. this class implements a kind of function chaining.
|
||||
struct AdaptedField : BaseOptionField {
|
||||
void* LookupImpl(Options* options) const override {
|
||||
return original->LookupImpl((options->*get_child)());
|
||||
}
|
||||
|
||||
AdaptedField(
|
||||
std::shared_ptr<OriginalField> original,
|
||||
ChildOptions* (Options::* get_child)())
|
||||
: original(original), get_child(get_child) {}
|
||||
|
||||
std::shared_ptr<OriginalField> original;
|
||||
ChildOptions* (Options::* get_child)();
|
||||
};
|
||||
|
||||
return std::shared_ptr<BaseOptionField>(
|
||||
new AdaptedField(original, get_child));
|
||||
}
|
||||
template <typename Options>
|
||||
template <typename ChildOptions>
|
||||
auto OptionsParser<Options>::Convert(
|
||||
typename OptionsParser<ChildOptions>::OptionInfo original,
|
||||
ChildOptions* (Options::* get_child)()) {
|
||||
return OptionInfo {
|
||||
original.type,
|
||||
Convert(original.field, get_child),
|
||||
original.env_setting
|
||||
};
|
||||
}
|
||||
|
||||
template <typename Options>
|
||||
template <typename ChildOptions>
|
||||
auto OptionsParser<Options>::Convert(
|
||||
typename OptionsParser<ChildOptions>::Implication original,
|
||||
ChildOptions* (Options::* get_child)()) {
|
||||
return Implication {
|
||||
std::static_pointer_cast<OptionField<bool>>(
|
||||
Convert(original.target_field, get_child)),
|
||||
original.target_value
|
||||
};
|
||||
}
|
||||
|
||||
template <typename Options>
|
||||
template <typename ChildOptions>
|
||||
void OptionsParser<Options>::Insert(
|
||||
OptionsParser<ChildOptions>* child_options_parser,
|
||||
ChildOptions* (Options::* get_child)()) {
|
||||
aliases_.insert(child_options_parser->aliases_.begin(),
|
||||
child_options_parser->aliases_.end());
|
||||
|
||||
for (const auto& pair : child_options_parser->options_)
|
||||
options_.emplace(pair.first, Convert(pair.second, get_child));
|
||||
|
||||
for (const auto& pair : child_options_parser->implications_)
|
||||
implications_.emplace(pair.first, Convert(pair.second, get_child));
|
||||
}
|
||||
|
||||
inline std::string NotAllowedInEnvErr(const std::string& arg) {
|
||||
return arg + " is not allowed in NODE_OPTIONS";
|
||||
}
|
||||
|
||||
inline std::string RequiresArgumentErr(const std::string& arg) {
|
||||
return arg + " requires an argument";
|
||||
}
|
||||
|
||||
// We store some of the basic information around a single Parse call inside
|
||||
// this struct, to separate storage of command line arguments and their
|
||||
// handling. In particular, this makes it easier to introduce 'synthetic'
|
||||
// arguments that get inserted by expanding option aliases.
|
||||
struct ArgsInfo {
|
||||
// Generally, the idea here is that the first entry in `*underlying` stores
|
||||
// the "0th" argument (the program name), then `synthetic_args` are inserted,
|
||||
// followed by the remainder of `*underlying`.
|
||||
std::vector<std::string>* underlying;
|
||||
std::vector<std::string> synthetic_args;
|
||||
|
||||
std::vector<std::string>* exec_args;
|
||||
|
||||
ArgsInfo(std::vector<std::string>* args,
|
||||
std::vector<std::string>* exec_args)
|
||||
: underlying(args), exec_args(exec_args) {}
|
||||
|
||||
size_t remaining() const {
|
||||
// -1 to account for the program name.
|
||||
return underlying->size() - 1 + synthetic_args.size();
|
||||
}
|
||||
|
||||
bool empty() const { return remaining() == 0; }
|
||||
const std::string& program_name() const { return underlying->at(0); }
|
||||
|
||||
std::string& first() {
|
||||
return synthetic_args.empty() ? underlying->at(1) : synthetic_args.front();
|
||||
}
|
||||
|
||||
std::string pop_first() {
|
||||
std::string ret = std::move(first());
|
||||
if (synthetic_args.empty()) {
|
||||
// Only push arguments to `exec_args` that were also originally passed
|
||||
// on the command line (i.e. not generated through alias expansion).
|
||||
// '--' is a special case here since its purpose is to end `exec_argv`,
|
||||
// which is why we do not include it.
|
||||
if (exec_args != nullptr && first() != "--")
|
||||
exec_args->push_back(ret);
|
||||
underlying->erase(underlying->begin() + 1);
|
||||
} else {
|
||||
synthetic_args.erase(synthetic_args.begin());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Options>
|
||||
void OptionsParser<Options>::Parse(
|
||||
std::vector<std::string>* const orig_args,
|
||||
std::vector<std::string>* const exec_args,
|
||||
std::vector<std::string>* const v8_args,
|
||||
Options* const options,
|
||||
OptionEnvvarSettings required_env_settings,
|
||||
std::string* const error) {
|
||||
ArgsInfo args(orig_args, exec_args);
|
||||
|
||||
// The first entry is the process name. Make sure it ends up in the V8 argv,
|
||||
// since V8::SetFlagsFromCommandLine() expects that to hold true for that
|
||||
// array as well.
|
||||
if (v8_args->empty())
|
||||
v8_args->push_back(args.program_name());
|
||||
|
||||
while (!args.empty() && error->empty()) {
|
||||
if (args.first().size() <= 1 || args.first()[0] != '-') break;
|
||||
|
||||
// We know that we're either going to consume this
|
||||
// argument or fail completely.
|
||||
const std::string arg = args.pop_first();
|
||||
|
||||
if (arg == "--") {
|
||||
if (required_env_settings == kAllowedInEnvironment)
|
||||
*error = NotAllowedInEnvErr("--");
|
||||
break;
|
||||
}
|
||||
|
||||
// Only allow --foo=bar notation for options starting with double dashes.
|
||||
// (E.g. -e=a is not allowed as shorthand for --eval=a, which would
|
||||
// otherwise be the result of alias expansion.)
|
||||
const std::string::size_type equals_index =
|
||||
arg[0] == '-' && arg[1] == '-' ? arg.find('=') : std::string::npos;
|
||||
std::string name =
|
||||
equals_index == std::string::npos ? arg : arg.substr(0, equals_index);
|
||||
|
||||
// Store the 'original name' of the argument. This name differs from
|
||||
// 'name' in that it contains a possible '=' sign and is not affected
|
||||
// by alias expansion.
|
||||
std::string original_name = name;
|
||||
if (equals_index != std::string::npos)
|
||||
original_name += '=';
|
||||
|
||||
{
|
||||
auto it = aliases_.end();
|
||||
// Expand aliases:
|
||||
// - If `name` can be found in `aliases_`.
|
||||
// - If `name` + '=' can be found in `aliases_`.
|
||||
// - If `name` + " <arg>" can be found in `aliases_`, and we have
|
||||
// a subsequent argument that does not start with '-' itself.
|
||||
while ((it = aliases_.find(name)) != aliases_.end() ||
|
||||
(equals_index != std::string::npos &&
|
||||
(it = aliases_.find(name + '=')) != aliases_.end()) ||
|
||||
(!args.empty() &&
|
||||
!args.first().empty() &&
|
||||
args.first()[0] != '-' &&
|
||||
(it = aliases_.find(name + " <arg>")) != aliases_.end())) {
|
||||
const std::string prev_name = std::move(name);
|
||||
const std::vector<std::string>& expansion = it->second;
|
||||
|
||||
// Use the first entry in the expansion as the new 'name'.
|
||||
name = expansion.front();
|
||||
|
||||
if (expansion.size() > 1) {
|
||||
// The other arguments, if any, are going to be handled later.
|
||||
args.synthetic_args.insert(
|
||||
args.synthetic_args.begin(),
|
||||
expansion.begin() + 1,
|
||||
expansion.end());
|
||||
}
|
||||
|
||||
if (name == prev_name) break;
|
||||
}
|
||||
}
|
||||
|
||||
auto it = options_.find(name);
|
||||
|
||||
if (it == options_.end()) {
|
||||
// We would assume that this is a V8 option if neither we nor any child
|
||||
// parser knows about it, so we convert - to _ for
|
||||
// canonicalization (since V8 accepts both) and look up again in order
|
||||
// to find a match.
|
||||
// TODO(addaleax): Make the canonicalization unconditional, i.e. allow
|
||||
// both - and _ in Node's own options as well.
|
||||
std::string::size_type index = 2; // Start after initial '--'.
|
||||
while ((index = name.find('-', index + 1)) != std::string::npos)
|
||||
name[index] = '_';
|
||||
it = options_.find(name);
|
||||
}
|
||||
|
||||
if ((it == options_.end() ||
|
||||
it->second.env_setting == kDisallowedInEnvironment) &&
|
||||
required_env_settings == kAllowedInEnvironment) {
|
||||
*error = NotAllowedInEnvErr(original_name);
|
||||
break;
|
||||
}
|
||||
|
||||
if (it == options_.end()) {
|
||||
v8_args->push_back(arg);
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
auto implications = implications_.equal_range(name);
|
||||
for (auto it = implications.first; it != implications.second; ++it)
|
||||
*it->second.target_field->Lookup(options) = it->second.target_value;
|
||||
}
|
||||
|
||||
const OptionInfo& info = it->second;
|
||||
std::string value;
|
||||
if (info.type != kBoolean && info.type != kNoOp && info.type != kV8Option) {
|
||||
if (equals_index != std::string::npos) {
|
||||
value = arg.substr(equals_index + 1);
|
||||
if (value.empty()) {
|
||||
missing_argument:
|
||||
*error = RequiresArgumentErr(original_name);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (args.empty())
|
||||
goto missing_argument;
|
||||
|
||||
value = args.pop_first();
|
||||
|
||||
if (!value.empty() && value[0] == '-') {
|
||||
goto missing_argument;
|
||||
} else {
|
||||
if (!value.empty() && value[0] == '\\' && value[1] == '-')
|
||||
value = value.substr(1); // Treat \- as escaping an -.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (info.type) {
|
||||
case kBoolean:
|
||||
*std::static_pointer_cast<OptionField<bool>>(info.field)
|
||||
->Lookup(options) = true;
|
||||
break;
|
||||
case kInteger:
|
||||
*std::static_pointer_cast<OptionField<int64_t>>(info.field)
|
||||
->Lookup(options) = std::atoll(value.c_str());
|
||||
break;
|
||||
case kString:
|
||||
*std::static_pointer_cast<OptionField<std::string>>(info.field)
|
||||
->Lookup(options) = value;
|
||||
break;
|
||||
case kStringList:
|
||||
std::static_pointer_cast<OptionField<std::vector<std::string>>>(
|
||||
info.field)->Lookup(options)->emplace_back(std::move(value));
|
||||
break;
|
||||
case kHostPort:
|
||||
std::static_pointer_cast<OptionField<HostPort>>(info.field)
|
||||
->Lookup(options)->Update(SplitHostPort(value, error));
|
||||
break;
|
||||
case kNoOp:
|
||||
break;
|
||||
case kV8Option:
|
||||
v8_args->push_back(arg);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace node
|
||||
|
||||
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#endif // SRC_NODE_OPTIONS_INL_H_
|
||||
219
src/node_options.cc
Normal file
219
src/node_options.cc
Normal file
@@ -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
|
||||
356
src/node_options.h
Normal file
356
src/node_options.h
Normal file
@@ -0,0 +1,356 @@
|
||||
#ifndef SRC_NODE_OPTIONS_H_
|
||||
#define SRC_NODE_OPTIONS_H_
|
||||
|
||||
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include "node_constants.h"
|
||||
|
||||
namespace node {
|
||||
|
||||
struct HostPort {
|
||||
std::string host_name;
|
||||
int port;
|
||||
|
||||
void Update(const HostPort& other) {
|
||||
if (!other.host_name.empty()) host_name = other.host_name;
|
||||
if (other.port >= 0) port = other.port;
|
||||
}
|
||||
};
|
||||
|
||||
// These options are currently essentially per-Environment, but it can be nice
|
||||
// to keep them separate since they are a group of options applying to a very
|
||||
// specific part of Node. It might also make more sense for them to be
|
||||
// per-Isolate, rather than per-Environment.
|
||||
class DebugOptions {
|
||||
public:
|
||||
bool inspector_enabled = false;
|
||||
bool deprecated_debug = false;
|
||||
bool break_first_line = false;
|
||||
bool break_node_first_line = false;
|
||||
HostPort host_port = {"127.0.0.1", -1};
|
||||
enum { kDefaultInspectorPort = 9229 };
|
||||
|
||||
bool deprecated_invocation() const {
|
||||
return deprecated_debug &&
|
||||
inspector_enabled &&
|
||||
break_first_line;
|
||||
}
|
||||
|
||||
bool invalid_invocation() const {
|
||||
return deprecated_debug && !inspector_enabled;
|
||||
}
|
||||
|
||||
bool wait_for_connect() const {
|
||||
return break_first_line || break_node_first_line;
|
||||
}
|
||||
|
||||
const std::string& host() {
|
||||
return host_port.host_name;
|
||||
}
|
||||
|
||||
int port() {
|
||||
return host_port.port < 0 ? kDefaultInspectorPort : host_port.port;
|
||||
}
|
||||
};
|
||||
|
||||
class EnvironmentOptions {
|
||||
public:
|
||||
std::shared_ptr<DebugOptions> debug_options { new DebugOptions() };
|
||||
bool experimental_modules = false;
|
||||
bool experimental_repl_await = false;
|
||||
bool experimental_vm_modules = false;
|
||||
bool experimental_worker = false;
|
||||
bool expose_internals = false;
|
||||
bool no_deprecation = false;
|
||||
bool no_force_async_hooks_checks = false;
|
||||
bool no_warnings = false;
|
||||
bool pending_deprecation = false;
|
||||
bool preserve_symlinks = false;
|
||||
bool preserve_symlinks_main = false;
|
||||
bool prof_process = false;
|
||||
std::string redirect_warnings;
|
||||
bool throw_deprecation = false;
|
||||
bool trace_deprecation = false;
|
||||
bool trace_sync_io = false;
|
||||
bool trace_warnings = false;
|
||||
std::string userland_loader;
|
||||
|
||||
bool syntax_check_only = false;
|
||||
bool has_eval_string = false;
|
||||
std::string eval_string;
|
||||
bool print_eval = false;
|
||||
bool force_repl = false;
|
||||
|
||||
std::vector<std::string> preload_modules;
|
||||
|
||||
std::vector<std::string> user_argv;
|
||||
|
||||
inline DebugOptions* get_debug_options();
|
||||
};
|
||||
|
||||
class PerIsolateOptions {
|
||||
public:
|
||||
std::shared_ptr<EnvironmentOptions> per_env { new EnvironmentOptions() };
|
||||
bool track_heap_objects = false;
|
||||
|
||||
inline EnvironmentOptions* get_per_env_options();
|
||||
};
|
||||
|
||||
class PerProcessOptions {
|
||||
public:
|
||||
std::shared_ptr<PerIsolateOptions> per_isolate { new PerIsolateOptions() };
|
||||
|
||||
std::string title;
|
||||
std::string trace_event_categories;
|
||||
std::string trace_event_file_pattern = "node_trace.${rotation}.log";
|
||||
int64_t v8_thread_pool_size = 4;
|
||||
bool zero_fill_all_buffers = false;
|
||||
|
||||
std::vector<std::string> security_reverts;
|
||||
bool print_help = false;
|
||||
bool print_v8_help = false;
|
||||
bool print_version = false;
|
||||
|
||||
#ifdef NODE_HAVE_I18N_SUPPORT
|
||||
std::string icu_data_dir;
|
||||
#endif
|
||||
|
||||
// TODO(addaleax): Some of these could probably be per-Environment.
|
||||
#if HAVE_OPENSSL
|
||||
std::string openssl_config;
|
||||
std::string tls_cipher_list = DEFAULT_CIPHER_LIST_CORE;
|
||||
#ifdef NODE_OPENSSL_CERT_STORE
|
||||
bool ssl_openssl_cert_store = true;
|
||||
#else
|
||||
bool ssl_openssl_cert_store = false;
|
||||
#endif
|
||||
bool use_openssl_ca = false;
|
||||
bool use_bundled_ca = false;
|
||||
#if NODE_FIPS_MODE
|
||||
bool enable_fips_crypto = false;
|
||||
bool force_fips_crypto = false;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
inline PerIsolateOptions* get_per_isolate_options();
|
||||
};
|
||||
|
||||
// The actual options parser, as opposed to the structs containing them:
|
||||
|
||||
HostPort SplitHostPort(const std::string& arg, std::string* error);
|
||||
|
||||
enum OptionEnvvarSettings {
|
||||
kAllowedInEnvironment,
|
||||
kDisallowedInEnvironment
|
||||
};
|
||||
|
||||
enum OptionType {
|
||||
kNoOp,
|
||||
kV8Option,
|
||||
kBoolean,
|
||||
kInteger,
|
||||
kString,
|
||||
kHostPort,
|
||||
kStringList,
|
||||
};
|
||||
|
||||
template <typename Options>
|
||||
class OptionsParser {
|
||||
public:
|
||||
virtual ~OptionsParser() {}
|
||||
|
||||
typedef Options TargetType;
|
||||
|
||||
struct NoOp {};
|
||||
struct V8Option {};
|
||||
|
||||
// TODO(addaleax): A lot of the `std::string` usage here could be reduced
|
||||
// to simple `const char*`s if it's reasonable to expect the values to be
|
||||
// known at compile-time.
|
||||
|
||||
// These methods add a single option to the parser. Optionally, it can be
|
||||
// specified whether the option should be allowed from environment variable
|
||||
// sources (i.e. NODE_OPTIONS).
|
||||
void AddOption(const std::string& name,
|
||||
bool Options::* field,
|
||||
OptionEnvvarSettings env_setting = kDisallowedInEnvironment);
|
||||
void AddOption(const std::string& name,
|
||||
int64_t Options::* field,
|
||||
OptionEnvvarSettings env_setting = kDisallowedInEnvironment);
|
||||
void AddOption(const std::string& name,
|
||||
std::string Options::* field,
|
||||
OptionEnvvarSettings env_setting = kDisallowedInEnvironment);
|
||||
void AddOption(const std::string& name,
|
||||
std::vector<std::string> Options::* field,
|
||||
OptionEnvvarSettings env_setting = kDisallowedInEnvironment);
|
||||
void AddOption(const std::string& name,
|
||||
HostPort Options::* field,
|
||||
OptionEnvvarSettings env_setting = kDisallowedInEnvironment);
|
||||
void AddOption(const std::string& name,
|
||||
NoOp no_op_tag,
|
||||
OptionEnvvarSettings env_setting = kDisallowedInEnvironment);
|
||||
void AddOption(const std::string& name,
|
||||
V8Option v8_option_tag,
|
||||
OptionEnvvarSettings env_setting = kDisallowedInEnvironment);
|
||||
|
||||
// Adds aliases. An alias can be of the form "--option-a" -> "--option-b",
|
||||
// or have a more complex group expansion, like
|
||||
// "--option-a" -> { "--option-b", "--harmony-foobar", "--eval", "42" }
|
||||
// If `from` has the form "--option-a=", the alias will only be expanded if
|
||||
// the option is presented in that form (i.e. with a '=').
|
||||
// If `from` has the form "--option-a <arg>", the alias will only be expanded
|
||||
// if the option has a non-option argument (not starting with -) following it.
|
||||
void AddAlias(const std::string& from, const std::string& to);
|
||||
void AddAlias(const std::string& from, const std::vector<std::string>& to);
|
||||
void AddAlias(const std::string& from,
|
||||
const std::initializer_list<std::string>& to);
|
||||
|
||||
// Add implications from some arbitary option to a boolean one, either
|
||||
// in a way that makes `from` set `to` to true or to false.
|
||||
void Implies(const std::string& from, const std::string& to);
|
||||
void ImpliesNot(const std::string& from, const std::string& to);
|
||||
|
||||
// Insert options from another options parser into this one, along with
|
||||
// a method that yields the target options type from this parser's options
|
||||
// type.
|
||||
template <typename ChildOptions>
|
||||
void Insert(OptionsParser<ChildOptions>* child_options_parser,
|
||||
ChildOptions* (Options::* get_child)());
|
||||
|
||||
// Parse a sequence of options into an options struct, a list of
|
||||
// arguments that were parsed as options, a list of unknown/JS engine options,
|
||||
// and leave the remainder in the input `args` vector.
|
||||
//
|
||||
// For example, an `args` input of
|
||||
//
|
||||
// node --foo --harmony-bar --fizzle=42 -- /path/to/cow moo
|
||||
//
|
||||
// expands as
|
||||
//
|
||||
// - `args` -> { "node", "/path/to/cow", "moo" }
|
||||
// - `exec_args` -> { "--foo", "--harmony-bar", "--fizzle=42" }
|
||||
// - `v8_args` -> `{ "node", "--harmony-bar" }
|
||||
// - `options->foo == true`, `options->fizzle == 42`.
|
||||
//
|
||||
// If `*error` is set, the result of the parsing should be discarded and the
|
||||
// contents of any of the argument vectors should be considered undefined.
|
||||
virtual void Parse(std::vector<std::string>* const args,
|
||||
std::vector<std::string>* const exec_args,
|
||||
std::vector<std::string>* const v8_args,
|
||||
Options* const options,
|
||||
OptionEnvvarSettings required_env_settings,
|
||||
std::string* const error);
|
||||
|
||||
private:
|
||||
// We support the wide variety of different option types by remembering
|
||||
// how to access them, given a certain `Options` struct.
|
||||
|
||||
// Represents a field within `Options`.
|
||||
class BaseOptionField {
|
||||
public:
|
||||
virtual ~BaseOptionField() {}
|
||||
virtual void* LookupImpl(Options* options) const = 0;
|
||||
};
|
||||
|
||||
// Represents a field of type T within `Options`.
|
||||
template <typename T>
|
||||
class OptionField : public BaseOptionField {
|
||||
public:
|
||||
typedef T Type;
|
||||
|
||||
T* Lookup(Options* options) const {
|
||||
return static_cast<T*>(this->LookupImpl(options));
|
||||
}
|
||||
};
|
||||
|
||||
// Represents a field of type T withing `Options` that can be looked up
|
||||
// as a C++ member field.
|
||||
template <typename T>
|
||||
class SimpleOptionField : public OptionField<T> {
|
||||
public:
|
||||
explicit SimpleOptionField(T Options::* field) : field_(field) {}
|
||||
void* LookupImpl(Options* options) const override {
|
||||
return static_cast<void*>(&(options->*field_));
|
||||
}
|
||||
|
||||
private:
|
||||
T Options::* field_;
|
||||
};
|
||||
|
||||
// An option consists of:
|
||||
// - A type.
|
||||
// - A way to store/access the property value.
|
||||
// - The information of whether it may occur in an env var or not.
|
||||
struct OptionInfo {
|
||||
OptionType type;
|
||||
std::shared_ptr<BaseOptionField> field;
|
||||
OptionEnvvarSettings env_setting;
|
||||
};
|
||||
|
||||
// An implied option is composed of the information on where to store a
|
||||
// specific boolean value (if another specific option is encountered).
|
||||
struct Implication {
|
||||
std::shared_ptr<OptionField<bool>> target_field;
|
||||
bool target_value;
|
||||
};
|
||||
|
||||
// These are helpers that make `Insert()` support properties of other
|
||||
// options structs, if we know how to access them.
|
||||
template <typename OriginalField, typename ChildOptions>
|
||||
static auto Convert(
|
||||
std::shared_ptr<OriginalField> original,
|
||||
ChildOptions* (Options::* get_child)());
|
||||
template <typename ChildOptions>
|
||||
static auto Convert(
|
||||
typename OptionsParser<ChildOptions>::OptionInfo original,
|
||||
ChildOptions* (Options::* get_child)());
|
||||
template <typename ChildOptions>
|
||||
static auto Convert(
|
||||
typename OptionsParser<ChildOptions>::Implication original,
|
||||
ChildOptions* (Options::* get_child)());
|
||||
|
||||
std::unordered_map<std::string, OptionInfo> options_;
|
||||
std::unordered_map<std::string, std::vector<std::string>> aliases_;
|
||||
std::unordered_multimap<std::string, Implication> implications_;
|
||||
|
||||
template <typename OtherOptions>
|
||||
friend class OptionsParser;
|
||||
};
|
||||
|
||||
class DebugOptionsParser : public OptionsParser<DebugOptions> {
|
||||
public:
|
||||
DebugOptionsParser();
|
||||
|
||||
static DebugOptionsParser instance;
|
||||
};
|
||||
|
||||
class EnvironmentOptionsParser : public OptionsParser<EnvironmentOptions> {
|
||||
public:
|
||||
EnvironmentOptionsParser();
|
||||
|
||||
static EnvironmentOptionsParser instance;
|
||||
};
|
||||
|
||||
class PerIsolateOptionsParser : public OptionsParser<PerIsolateOptions> {
|
||||
public:
|
||||
PerIsolateOptionsParser();
|
||||
|
||||
static PerIsolateOptionsParser instance;
|
||||
};
|
||||
|
||||
class PerProcessOptionsParser : public OptionsParser<PerProcessOptions> {
|
||||
public:
|
||||
PerProcessOptionsParser();
|
||||
|
||||
static PerProcessOptionsParser instance;
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
||||
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#endif // SRC_NODE_OPTIONS_H_
|
||||
@@ -104,7 +104,9 @@ Worker::Worker(Environment* env, Local<Object> wrap)
|
||||
env_->set_worker_context(this);
|
||||
env_->set_thread_id(thread_id_);
|
||||
|
||||
env_->Start(0, nullptr, 0, nullptr, env->profiler_idle_notifier_started());
|
||||
env_->Start(std::vector<std::string>{},
|
||||
std::vector<std::string>{},
|
||||
env->profiler_idle_notifier_started());
|
||||
}
|
||||
|
||||
// The new isolate won't be bothered on this thread again.
|
||||
|
||||
Reference in New Issue
Block a user