feat: enable passing Node.js cli flags (#21110)

* feat: enable passing Node.js cli flags

* Allow cli flags in ELECTRON_RUN_AS_NODE mode
This commit is contained in:
Shelley Vohr 2020-02-07 02:59:38 +00:00 коммит произвёл GitHub
Родитель 9107157073
Коммит 83124889e5
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 484 добавлений и 202 удалений

Просмотреть файл

@ -16,80 +16,66 @@ app.whenReady().then(() => {
})
```
## --ignore-connections-limit=`domains`
## Electron CLI Flags
Ignore the connections limit for `domains` list separated by `,`.
### --auth-server-whitelist=`url`
## --disable-http-cache
Disables the disk cache for HTTP requests.
## --disable-http2
Disable HTTP/2 and SPDY/3.1 protocols.
## --lang
Set a custom locale.
## --inspect=`port` and --inspect-brk=`port`
Debug-related flags, see the [Debugging the Main Process][debugging-main-process] guide for details.
## --remote-debugging-port=`port`
Enables remote debugging over HTTP on the specified `port`.
## --disk-cache-size=`size`
Forces the maximum disk space to be used by the disk cache, in bytes.
## --js-flags=`flags`
Specifies the flags passed to the Node.js engine. It has to be passed when starting
Electron if you want to enable the `flags` in the main process.
```sh
$ electron --js-flags="--harmony_proxies --harmony_collections" your-app
```
See the [Node.js documentation][node-cli] or run `node --help` in your terminal for a list of available flags. Additionally, run `node --v8-options` to see a list of flags that specifically refer to Node.js's V8 JavaScript engine.
## --proxy-server=`address:port`
Use a specified proxy server, which overrides the system setting. This switch
only affects requests with HTTP protocol, including HTTPS and WebSocket
requests. It is also noteworthy that not all proxy servers support HTTPS and
WebSocket requests. The proxy URL does not support username and password
authentication [per Chromium issue](https://bugs.chromium.org/p/chromium/issues/detail?id=615947).
## --proxy-bypass-list=`hosts`
Instructs Electron to bypass the proxy server for the given semi-colon-separated
list of hosts. This flag has an effect only if used in tandem with
`--proxy-server`.
A comma-separated list of servers for which integrated authentication is enabled.
For example:
```javascript
const { app } = require('electron')
app.commandLine.appendSwitch('proxy-bypass-list', '<local>;*.google.com;*foo.com;1.2.3.4:5678')
```sh
--auth-server-whitelist='*example.com, *foobar.com, *baz'
```
Will use the proxy server for all hosts except for local addresses (`localhost`,
`127.0.0.1` etc.), `google.com` subdomains, hosts that contain the suffix
`foo.com` and anything at `1.2.3.4:5678`.
then any `url` ending with `example.com`, `foobar.com`, `baz` will be considered
for integrated authentication. Without `*` prefix the URL has to match exactly.
## --proxy-pac-url=`url`
### --auth-negotiate-delegate-whitelist=`url`
Uses the PAC script at the specified `url`.
A comma-separated list of servers for which delegation of user credentials is required.
Without `*` prefix the URL has to match exactly.
## --no-proxy-server
### --disable-http-cache
Don't use a proxy server and always make direct connections. Overrides any other
proxy server flags that are passed.
Disables the disk cache for HTTP requests.
## --host-rules=`rules`
### --disable-http2
Disable HTTP/2 and SPDY/3.1 protocols.
### --disable-renderer-backgrounding
Prevents Chromium from lowering the priority of invisible pages' renderer
processes.
This flag is global to all renderer processes, if you only want to disable
throttling in one window, you can take the hack of
[playing silent audio][play-silent-audio].
### --disk-cache-size=`size`
Forces the maximum disk space to be used by the disk cache, in bytes.
### --enable-api-filtering-logging
Enables caller stack logging for the following APIs (filtering events):
- `desktopCapturer.getSources()` / `desktop-capturer-get-sources`
- `remote.require()` / `remote-require`
- `remote.getGlobal()` / `remote-get-builtin`
- `remote.getBuiltin()` / `remote-get-global`
- `remote.getCurrentWindow()` / `remote-get-current-window`
- `remote.getCurrentWebContents()` / `remote-get-current-web-contents`
### --enable-logging
Prints Chromium's logging into console.
This switch can not be used in `app.commandLine.appendSwitch` since it is parsed
earlier than user's app is loaded, but you can set the `ELECTRON_ENABLE_LOGGING`
environment variable to achieve the same effect.
### --host-rules=`rules`
A comma-separated list of `rules` that control how hostnames are mapped.
@ -107,69 +93,96 @@ These mappings apply to the endpoint host in a net request (the TCP connect
and host resolver in a direct connection, and the `CONNECT` in an HTTP proxy
connection, and the endpoint host in a `SOCKS` proxy connection).
## --host-resolver-rules=`rules`
### --host-resolver-rules=`rules`
Like `--host-rules` but these `rules` only apply to the host resolver.
## --auth-server-whitelist=`url`
A comma-separated list of servers for which integrated authentication is enabled.
For example:
```sh
--auth-server-whitelist='*example.com, *foobar.com, *baz'
```
then any `url` ending with `example.com`, `foobar.com`, `baz` will be considered
for integrated authentication. Without `*` prefix the URL has to match exactly.
## --auth-negotiate-delegate-whitelist=`url`
A comma-separated list of servers for which delegation of user credentials is required.
Without `*` prefix the URL has to match exactly.
## --ignore-certificate-errors
### --ignore-certificate-errors
Ignores certificate related errors.
## --ppapi-flash-path=`path`
### --ignore-connections-limit=`domains`
Sets the `path` of the pepper flash plugin.
Ignore the connections limit for `domains` list separated by `,`.
## --ppapi-flash-version=`version`
### --js-flags=`flags`
Sets the `version` of the pepper flash plugin.
Specifies the flags passed to the Node.js engine. It has to be passed when starting
Electron if you want to enable the `flags` in the main process.
## --log-net-log=`path`
```sh
$ electron --js-flags="--harmony_proxies --harmony_collections" your-app
```
See the [Node.js documentation][node-cli] or run `node --help` in your terminal for a list of available flags. Additionally, run `node --v8-options` to see a list of flags that specifically refer to Node.js's V8 JavaScript engine.
### --lang
Set a custom locale.
### --log-net-log=`path`
Enables net log events to be saved and writes them to `path`.
## --disable-renderer-backgrounding
### --no-proxy-server
Prevents Chromium from lowering the priority of invisible pages' renderer
processes.
Don't use a proxy server and always make direct connections. Overrides any other
proxy server flags that are passed.
This flag is global to all renderer processes, if you only want to disable
throttling in one window, you can take the hack of
[playing silent audio][play-silent-audio].
### --no-sandbox
## --enable-logging
Disables Chromium sandbox, which is now enabled by default.
Should only be used for testing.
Prints Chromium's logging into console.
### --proxy-bypass-list=`hosts`
This switch can not be used in `app.commandLine.appendSwitch` since it is parsed
earlier than user's app is loaded, but you can set the `ELECTRON_ENABLE_LOGGING`
environment variable to achieve the same effect.
Instructs Electron to bypass the proxy server for the given semi-colon-separated
list of hosts. This flag has an effect only if used in tandem with
`--proxy-server`.
## --v=`log_level`
For example:
```javascript
const { app } = require('electron')
app.commandLine.appendSwitch('proxy-bypass-list', '<local>;*.google.com;*foo.com;1.2.3.4:5678')
```
Will use the proxy server for all hosts except for local addresses (`localhost`,
`127.0.0.1` etc.), `google.com` subdomains, hosts that contain the suffix
`foo.com` and anything at `1.2.3.4:5678`.
### --proxy-pac-url=`url`
Uses the PAC script at the specified `url`.
### --proxy-server=`address:port`
Use a specified proxy server, which overrides the system setting. This switch
only affects requests with HTTP protocol, including HTTPS and WebSocket
requests. It is also noteworthy that not all proxy servers support HTTPS and
WebSocket requests. The proxy URL does not support username and password
authentication [per Chromium issue](https://bugs.chromium.org/p/chromium/issues/detail?id=615947).
### --remote-debugging-port=`port`
Enables remote debugging over HTTP on the specified `port`.
### --ppapi-flash-path=`path`
Sets the `path` of the pepper flash plugin.
### --ppapi-flash-version=`version`
Sets the `version` of the pepper flash plugin.
### --v=`log_level`
Gives the default maximal active V-logging level; 0 is the default. Normally
positive values are used for V-logging levels.
This switch only works when `--enable-logging` is also passed.
## --vmodule=`pattern`
### --vmodule=`pattern`
Gives the per-module maximal V-logging levels to override the value given by
`--v`. E.g. `my_module=2,foo*=3` would change the logging level for all code in
@ -181,20 +194,38 @@ logging level for all code in the source files under a `foo/bar` directory.
This switch only works when `--enable-logging` is also passed.
## --enable-api-filtering-logging
## Node.js Flags
Enables caller stack logging for the following APIs (filtering events):
- `desktopCapturer.getSources()` / `desktop-capturer-get-sources`
- `remote.require()` / `remote-require`
- `remote.getGlobal()` / `remote-get-builtin`
- `remote.getBuiltin()` / `remote-get-global`
- `remote.getCurrentWindow()` / `remote-get-current-window`
- `remote.getCurrentWebContents()` / `remote-get-current-web-contents`
Electron supports some of the [CLI flags][node-cli] supported by Node.js.
## --no-sandbox
**Note:** Passing unsupported command line switches to Electron when it is not running in `ELECTRON_RUN_AS_NODE` will have no effect.
Disables Chromium sandbox, which is now enabled by default.
Should only be used for testing.
### --inspect-brk[=[host:]port]
Activate inspector on host:port and break at start of user script. Default host:port is 127.0.0.1:9229.
Aliased to `--debug-brk=[host:]port`.
### --inspect-port=[host:]port
Set the `host:port` to be used when the inspector is activated. Useful when activating the inspector by sending the SIGUSR1 signal. Default host is `127.0.0.1`.
Aliased to `--debug-port=[host:]port`.
### --inspect[=[host:]port]
Activate inspector on `host:port`. Default is `127.0.0.1:9229`.
V8 inspector integration allows tools such as Chrome DevTools and IDEs to debug and profile Electron instances. The tools attach to Electron instances via a tcp port and communicate using the [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/).
See the [Debugging the Main Process][debugging-main-process] guide for more details.
Aliased to `--debug[=[host:]port`.
### --inspect-publish-uid=stderr,http
Specify ways of the inspector web socket url exposure.
By default inspector websocket url is available in stderr and under /json/list endpoint on http://host:port/json/list.
[app]: app.md
[append-switch]: app.md#appcommandlineappendswitchswitch-value

Просмотреть файл

@ -80,6 +80,18 @@ and spawned child processes that set `ELECTRON_RUN_AS_NODE`.
Starts the process as a normal Node.js process.
In this mode, you will be able to pass [cli options](https://nodejs.org/api/cli.html) to Node.js as
you would when running the normal Node.js executable, with the exception of the following flags:
* "--openssl-config"
* "--use-bundled-ca"
* "--use-openssl-ca",
* "--force-fips"
* "--enable-fips"
These flags are disabled owing to the fact that Electron uses BoringSSL instead of OpenSSL when building Node.js'
`crypto` module, and so will not work as designed.
### `ELECTRON_NO_ATTACH_CONSOLE` _Windows_
Don't attach to the current console session.

Просмотреть файл

@ -36,3 +36,4 @@ remove_serialization_deserialization_of_wasmmoduleobject.patch
64bit_bump_typedarray_max_length_to_2_32-1_elements.patch
test_use_tmpdir_refresh_in_test-esm-windows_js.patch
override_existing_v8_reallocate.patch
feat_enable_passing_cli_flags.patch

Просмотреть файл

@ -0,0 +1,108 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shelley Vohr <shelley.vohr@gmail.com>
Date: Wed, 13 Nov 2019 15:39:48 +0000
Subject: feat: enable passing cli flags
This patches enables passing safelisted cli flags to Node.js.
Upstreamed in https://github.com/nodejs/node/pull/30466.
diff --git a/src/node.cc b/src/node.cc
index 461f736beacec67b35c89a42319f99178a1e38e9..c00bfb6ccbe603604fca29268d15d67b208b2e6a 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -113,8 +113,6 @@
namespace node {
using native_module::NativeModuleEnv;
-using options_parser::kAllowedInEnvironment;
-using options_parser::kDisallowedInEnvironment;
using v8::Boolean;
using v8::EscapableHandleScope;
@@ -670,7 +668,7 @@ void ResetStdio() {
int ProcessGlobalArgs(std::vector<std::string>* args,
std::vector<std::string>* exec_args,
std::vector<std::string>* errors,
- bool is_env) {
+ OptionEnvvarSettings settings) {
// Parse a few arguments which are specific to Node.
std::vector<std::string> v8_args;
@@ -680,7 +678,7 @@ int ProcessGlobalArgs(std::vector<std::string>* args,
exec_args,
&v8_args,
per_process::cli_options.get(),
- is_env ? kAllowedInEnvironment : kDisallowedInEnvironment,
+ settings,
errors);
if (!errors->empty()) return 9;
@@ -851,7 +849,7 @@ int InitializeNodeWithArgs(std::vector<std::string>* argv,
return 9;
}
- const int exit_code = ProcessGlobalArgs(&env_argv, nullptr, errors, true);
+ const int exit_code = ProcessGlobalArgs(&env_argv, nullptr, errors, kAllowedInEnvironment);
if (exit_code != 0) return exit_code;
}
#endif
@@ -859,7 +857,7 @@ int InitializeNodeWithArgs(std::vector<std::string>* argv,
if (g_upstream_node_mode) {
// NOTE(jeremy): indentation is intentionally wrong here, to ease rebasing.
- const int exit_code = ProcessGlobalArgs(argv, exec_argv, errors, false);
+ const int exit_code = ProcessGlobalArgs(argv, exec_argv, errors, kDisallowedInEnvironment);
if (exit_code != 0) return exit_code;
// Set the process.title immediately after processing argv if --title is set.
diff --git a/src/node.h b/src/node.h
index 9c6dcbf7014f7cf87f7f66886cbf255978c244fa..4f2da9a46966199465a33c1fa275d0116d395a56 100644
--- a/src/node.h
+++ b/src/node.h
@@ -223,6 +223,16 @@ NODE_EXTERN void Init(int* argc,
int* exec_argc,
const char*** exec_argv);
+enum OptionEnvvarSettings {
+ kAllowedInEnvironment,
+ kDisallowedInEnvironment
+};
+
+NODE_EXTERN int ProcessGlobalArgs(std::vector<std::string>* args,
+ std::vector<std::string>* exec_args,
+ std::vector<std::string>* errors,
+ OptionEnvvarSettings settings);
+
class NodeArrayBufferAllocator;
// An ArrayBuffer::Allocator class with some Node.js-specific tweaks. If you do
diff --git a/src/node_options.h b/src/node_options.h
index 4ce5551284bb5b1b4194905a9fe619f852933405..404cb72536cdaf8f0320770392e02ac75c303cae 100644
--- a/src/node_options.h
+++ b/src/node_options.h
@@ -248,11 +248,6 @@ HostPort NODE_EXTERN SplitHostPort(const std::string& arg,
std::vector<std::string>* errors);
void GetOptions(const v8::FunctionCallbackInfo<v8::Value>& args);
-enum OptionEnvvarSettings {
- kAllowedInEnvironment,
- kDisallowedInEnvironment
-};
-
enum OptionType {
kNoOp,
kV8Option,
diff --git a/src/node_worker.cc b/src/node_worker.cc
index c8b2e1699f26ac9bfeb373653d35271f9b6c841f..a4db86ad99c75e07960a95247a41ed78e5bf55ca 100644
--- a/src/node_worker.cc
+++ b/src/node_worker.cc
@@ -16,7 +16,7 @@
#include <string>
#include <vector>
-using node::options_parser::kDisallowedInEnvironment;
+using node::kDisallowedInEnvironment;
using v8::Array;
using v8::Boolean;
using v8::Context;

Просмотреть файл

@ -51,14 +51,8 @@
"parallel/test-buffer-constructor-node-modules-paths",
"parallel/test-buffer-constructor-outside-node-modules",
"parallel/test-child-process-fork-exec-path",
"parallel/test-child-process-windows-hide",
"parallel/test-cli-bad-options",
"parallel/test-cli-eval",
"parallel/test-cli-node-options",
"parallel/test-cli-node-print-help",
"parallel/test-cli-syntax-eval",
"parallel/test-cli-syntax-piped-bad",
"parallel/test-cli-syntax-piped-good",
"parallel/test-cli-eval",
"parallel/test-code-cache",
"parallel/test-common-gc",
"parallel/test-crypto",
@ -86,7 +80,6 @@
"parallel/test-debug-usage",
"parallel/test-debugger-pid",
"parallel/test-domain-abort-on-uncaught",
"parallel/test-domain-async-id-map-leak",
"parallel/test-domain-with-abort-on-uncaught-exception",
"parallel/test-dummy-stdio",
"parallel/test-freeze-intrinsics",
@ -108,8 +101,7 @@
"parallel/test-inspector-tracing-domain",
"parallel/test-inspector-vm-global-accessors-getter-sideeffect",
"parallel/test-inspector-vm-global-accessors-sideeffects",
"parallel/test-inspector-workers-flat-list",
"parallel/test-internal-util-weakreference",
"parallel/test-inspector-heap-allocation-tracker",
"parallel/test-module-loading-globalpaths",
"parallel/test-module-version",
"parallel/test-openssl-ca-options",
@ -121,12 +113,11 @@
"parallel/test-process-exception-capture",
"parallel/test-process-exception-capture-should-abort-on-uncaught",
"parallel/test-process-exception-capture-should-abort-on-uncaught-setflagsfromstring",
"parallel/test-process-exec-argv",
"parallel/test-process-exit-code",
"parallel/test-process-external-stdio-close",
"parallel/test-process-external-stdio-close-spawn",
"parallel/test-process-versions",
"parallel/test-readline-interface",
"parallel/test-inspector-tracing-domain",
"parallel/test-repl",
"parallel/test-repl-harmony",
"parallel/test-repl-pretty-custom-stack",
@ -136,7 +127,6 @@
"parallel/test-repl-tab-complete",
"parallel/test-repl-uncaught-exception",
"parallel/test-repl-underscore",
"parallel/test-security-revert-unknown",
"parallel/test-signal-handler",
"parallel/test-source-map",
"parallel/test-stdout-close-catch",
@ -242,9 +232,6 @@
"report/test-report-uncaught-exception",
"report/test-report-writereport",
"sequential/test-child-process-execsync",
"sequential/test-cli-syntax-bad",
"sequential/test-cli-syntax-good",
"sequential/test-cli-syntax-require",
"sequential/test-cpu-prof-default",
"sequential/test-cpu-prof-dir-absolute",
"sequential/test-cpu-prof-dir-and-name",
@ -252,11 +239,9 @@
"sequential/test-cpu-prof-dir-worker",
"sequential/test-cpu-prof-drained",
"sequential/test-cpu-prof-exit",
"sequential/test-cpu-prof-invalid-options",
"sequential/test-cpu-prof-kill",
"sequential/test-cpu-prof-name",
"sequential/test-cpu-prof-worker-argv",
"sequential/test-deprecation-flags",
"sequential/test-fs-watch",
"sequential/test-heap-prof",
"sequential/test-heapdump",

Просмотреть файл

@ -6,10 +6,14 @@
#include <memory>
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/threading/thread_task_runner_handle.h"
#include "electron/electron_version.h"
@ -29,6 +33,49 @@
#include "shell/common/crash_reporter/crash_reporter_win.h"
#endif
namespace {
// Initialize Node.js cli options to pass to Node.js
// See https://nodejs.org/api/cli.html#cli_options
void SetNodeCliFlags() {
// Options that are unilaterally disallowed
const std::unordered_set<base::StringPiece, base::StringPieceHash>
disallowed = {"--openssl-config", "--use-bundled-ca", "--use-openssl-ca",
"--force-fips", "--enable-fips"};
const auto argv = base::CommandLine::ForCurrentProcess()->argv();
std::vector<std::string> args;
// TODO(codebytere): We need to set the first entry in args to the
// process name owing to src/node_options-inl.h#L286-L290 but this is
// redundant and so should be refactored upstream.
args.reserve(argv.size() + 1);
args.emplace_back("electron");
for (const auto& arg : argv) {
#if defined(OS_WIN)
const auto& option = base::UTF16ToUTF8(arg);
#else
const auto& option = arg;
#endif
const auto stripped = base::StringPiece(option).substr(0, option.find('='));
if (disallowed.count(stripped) != 0) {
LOG(ERROR) << "The Node.js cli flag " << stripped
<< " is not supported in Electron";
} else {
args.push_back(option);
}
}
std::vector<std::string> errors;
// Node.js itself will output parsing errors to
// console so we don't need to handle that ourselves
ProcessGlobalArgs(&args, nullptr, &errors, node::kDisallowedInEnvironment);
}
} // namespace
namespace electron {
#if !defined(OS_LINUX)
@ -64,6 +111,9 @@ int NodeMain(int argc, char* argv[]) {
// Explicitly register electron's builtin modules.
NodeBindings::RegisterBuiltinModules();
// Parse and set Node.js cli flags.
SetNodeCliFlags();
int exec_argc;
const char** exec_argv;
node::Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);

Просмотреть файл

@ -41,9 +41,9 @@ void NodeDebugger::Start() {
std::vector<std::string> v8_args;
std::vector<std::string> errors;
// TODO(codebytere): remove this parsing and use ProcessGlobalArgs
node::options_parser::Parse(&args, &exec_args, &v8_args, &options,
node::options_parser::kDisallowedInEnvironment,
&errors);
node::kDisallowedInEnvironment, &errors);
if (!errors.empty()) {
// TODO(jeremy): what's the appropriate behaviour here?

Просмотреть файл

@ -8,6 +8,7 @@
#include <memory>
#include <set>
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>
@ -136,7 +137,51 @@ bool IsPackagedApp() {
#endif
}
// Initialize Node.js cli options to pass to Node.js
// See https://nodejs.org/api/cli.html#cli_options
void SetNodeCliFlags() {
// Only allow DebugOptions in non-ELECTRON_RUN_AS_NODE mode
const std::unordered_set<base::StringPiece, base::StringPieceHash> allowed = {
"--inspect", "--inspect-brk",
"--inspect-port", "--debug",
"--debug-brk", "--debug-port",
"--inspect-brk-node", "--inspect-publish-uid",
};
const auto argv = base::CommandLine::ForCurrentProcess()->argv();
std::vector<std::string> args;
// TODO(codebytere): We need to set the first entry in args to the
// process name owing to src/node_options-inl.h#L286-L290 but this is
// redundant and so should be refactored upstream.
args.reserve(argv.size() + 1);
args.emplace_back("electron");
for (const auto& arg : argv) {
#if defined(OS_WIN)
const auto& option = base::UTF16ToUTF8(arg);
#else
const auto& option = arg;
#endif
const auto stripped = base::StringPiece(option).substr(0, option.find('='));
if (allowed.count(stripped) != 0)
args.push_back(option);
}
std::vector<std::string> errors;
const int exit_code = ProcessGlobalArgs(&args, nullptr, &errors,
node::kDisallowedInEnvironment);
if (exit_code != 0) {
if (!errors.empty())
LOG(INFO) << base::JoinString(errors, " ");
else
LOG(INFO) << "Error parsing Node.js cli flags";
}
}
// Initialize NODE_OPTIONS to pass to Node.js
// See https://nodejs.org/api/cli.html#cli_node_options_options
void SetNodeOptions(base::Environment* env) {
// Options that are unilaterally disallowed
const std::set<std::string> disallowed = {
@ -157,7 +202,7 @@ void SetNodeOptions(base::Environment* env) {
for (const auto& part : parts) {
// Strip off values passed to individual NODE_OPTIONs
std::string option = part.substr(0, part.find("="));
std::string option = part.substr(0, part.find('='));
if (is_packaged_app &&
allowed_in_packaged.find(option) == allowed_in_packaged.end()) {
@ -270,6 +315,9 @@ void NodeBindings::Initialize() {
// Explicitly register electron's builtin modules.
RegisterBuiltinModules();
// Parse and set Node.js cli flags.
SetNodeCliFlags();
// pass non-null program name to argv so it doesn't crash
// trying to index into a nullptr
int argc = 1;

Просмотреть файл

@ -12,7 +12,7 @@ describe('node feature', () => {
const fixtures = path.join(__dirname, '..', 'spec', 'fixtures')
describe('child_process', () => {
describe('child_process.fork', () => {
it('works in browser process', (done) => {
it('Works in browser process', (done) => {
const child = childProcess.fork(path.join(fixtures, 'module', 'ping.js'))
child.on('message', (msg) => {
expect(msg).to.equal('message')
@ -25,11 +25,11 @@ describe('node feature', () => {
describe('contexts', () => {
describe('setTimeout called under Chromium event loop in browser process', () => {
it('can be scheduled in time', (done) => {
it('Can be scheduled in time', (done) => {
setTimeout(done, 0)
})
it('can be promisified', (done) => {
it('Can be promisified', (done) => {
util.promisify(setTimeout)(0).then(done)
})
})
@ -57,54 +57,104 @@ describe('node feature', () => {
let child: childProcess.ChildProcessWithoutNullStreams
let exitPromise: Promise<any[]>
afterEach(async () => {
if (child && exitPromise) {
it('Fails for options disallowed by Node.js itself', (done) => {
after(async () => {
const [code, signal] = await exitPromise
expect(signal).to.equal(null)
expect(code).to.equal(0)
} else if (child) {
child.kill()
}
})
it('fails for options disallowed by Node.js itself', (done) => {
// Exit code 9 indicates cli flag parsing failure
expect(code).to.equal(9)
child.kill()
})
const env = Object.assign({}, process.env, { NODE_OPTIONS: '--v8-options' })
child = childProcess.spawn(process.execPath, { env })
exitPromise = emittedOnce(child, 'exit')
function cleanup () {
let output = ''
let success = false
const cleanup = () => {
child.stderr.removeListener('data', listener)
child.stdout.removeListener('data', listener)
}
let output = ''
function listener (data: Buffer) {
const listener = (data: Buffer) => {
output += data
if (/electron: --v8-options is not allowed in NODE_OPTIONS/m.test(output)) {
success = true
cleanup()
done()
}
}
child.stderr.on('data', listener)
child.stdout.on('data', listener)
child.on('exit', () => {
if (!success) {
cleanup()
done(new Error(`Unexpected output: ${output.toString()}`))
}
})
})
it('disallows crypto-related options', (done) => {
it('Disallows crypto-related options', (done) => {
after(() => {
child.kill()
})
const env = Object.assign({}, process.env, { NODE_OPTIONS: '--use-openssl-ca' })
child = childProcess.spawn(process.execPath, ['--enable-logging'], { env })
function cleanup () {
let output = ''
const cleanup = () => {
child.stderr.removeListener('data', listener)
child.stdout.removeListener('data', listener)
}
let output = ''
function listener (data: Buffer) {
const listener = (data: Buffer) => {
output += data
if (/The NODE_OPTION --use-openssl-ca is not supported in Electron/m.test(output)) {
cleanup()
done()
}
}
child.stderr.on('data', listener)
child.stdout.on('data', listener)
})
})
describe('Node.js cli flags', () => {
let child: childProcess.ChildProcessWithoutNullStreams
let exitPromise: Promise<any[]>
it('Prohibits crypto-related flags in ELECTRON_RUN_AS_NODE mode', (done) => {
after(async () => {
const [code, signal] = await exitPromise
expect(signal).to.equal(null)
expect(code).to.equal(9)
child.kill()
})
child = childProcess.spawn(process.execPath, ['--force-fips'], {
env: { ELECTRON_RUN_AS_NODE: 'true' }
})
exitPromise = emittedOnce(child, 'exit')
let output = ''
const cleanup = () => {
child.stderr.removeListener('data', listener)
child.stdout.removeListener('data', listener)
}
const listener = (data: Buffer) => {
output += data
if (/.*The Node.js cli flag --force-fips is not supported in Electron/m.test(output)) {
cleanup()
done()
}
}
child.stderr.on('data', listener)
child.stdout.on('data', listener)
})
@ -124,72 +174,63 @@ describe('node feature', () => {
}
})
it('supports starting the v8 inspector with --inspect/--inspect-brk', (done) => {
it('Supports starting the v8 inspector with --inspect/--inspect-brk', (done) => {
child = childProcess.spawn(process.execPath, ['--inspect-brk', path.join(fixtures, 'module', 'run-as-node.js')], {
env: {
ELECTRON_RUN_AS_NODE: 'true'
}
env: { ELECTRON_RUN_AS_NODE: 'true' }
})
let output = ''
function cleanup () {
child.stderr.removeListener('data', errorDataListener)
child.stdout.removeListener('data', outDataHandler)
const cleanup = () => {
child.stderr.removeListener('data', listener)
child.stdout.removeListener('data', listener)
}
function errorDataListener (data: Buffer) {
const listener = (data: Buffer) => {
output += data
if (/^Debugger listening on ws:/m.test(output)) {
if (/Debugger listening on ws:/m.test(output)) {
cleanup()
done()
}
}
function outDataHandler (data: Buffer) {
cleanup()
done(new Error(`Unexpected output: ${data.toString()}`))
}
child.stderr.on('data', errorDataListener)
child.stdout.on('data', outDataHandler)
child.stderr.on('data', listener)
child.stdout.on('data', listener)
})
it('supports starting the v8 inspector with --inspect and a provided port', (done) => {
it('Supports starting the v8 inspector with --inspect and a provided port', (done) => {
child = childProcess.spawn(process.execPath, ['--inspect=17364', path.join(fixtures, 'module', 'run-as-node.js')], {
env: {
ELECTRON_RUN_AS_NODE: 'true'
}
env: { ELECTRON_RUN_AS_NODE: 'true' }
})
exitPromise = emittedOnce(child, 'exit')
let output = ''
function cleanup () {
child.stderr.removeListener('data', errorDataListener)
child.stdout.removeListener('data', outDataHandler)
const listener = (data: Buffer) => { output += data }
const cleanup = () => {
child.stderr.removeListener('data', listener)
child.stdout.removeListener('data', listener)
}
function errorDataListener (data: Buffer) {
output += data
child.stderr.on('data', listener)
child.stdout.on('data', listener)
child.on('exit', () => {
cleanup()
if (/^Debugger listening on ws:/m.test(output)) {
expect(output.trim()).to.contain(':17364', 'should be listening on port 17364')
cleanup()
done()
} else {
done(new Error(`Unexpected output: ${output.toString()}`))
}
}
function outDataHandler (data: Buffer) {
cleanup()
done(new Error(`Unexpected output: ${data.toString()}`))
}
child.stderr.on('data', errorDataListener)
child.stdout.on('data', outDataHandler)
})
})
it('does not start the v8 inspector when --inspect is after a -- argument', (done) => {
it('Does not start the v8 inspector when --inspect is after a -- argument', (done) => {
child = childProcess.spawn(process.execPath, [path.join(fixtures, 'module', 'noop.js'), '--', '--inspect'])
exitPromise = emittedOnce(child, 'exit')
let output = ''
function dataListener (data: Buffer) {
output += data
}
child.stderr.on('data', dataListener)
child.stdout.on('data', dataListener)
const listener = (data: Buffer) => { output += data }
child.stderr.on('data', listener)
child.stdout.on('data', listener)
child.on('exit', () => {
if (output.trim().startsWith('Debugger listening on ws://')) {
done(new Error('Inspector was started when it should not have been'))
@ -200,22 +241,24 @@ describe('node feature', () => {
})
// IPC Electron child process not supported on Windows
ifit(process.platform !== 'win32')('does does not crash when quitting with the inspector connected', function (done) {
ifit(process.platform !== 'win32')('Does does not crash when quitting with the inspector connected', function (done) {
child = childProcess.spawn(process.execPath, [path.join(fixtures, 'module', 'delay-exit'), '--inspect=0'], {
stdio: ['ipc']
}) as childProcess.ChildProcessWithoutNullStreams
exitPromise = emittedOnce(child, 'exit')
let output = ''
function dataListener (data: Buffer) {
output += data
const cleanup = () => {
child.stderr.removeListener('data', listener)
child.stdout.removeListener('data', listener)
}
let output = ''
let success = false
function listener (data: Buffer) {
output += data
if (output.trim().indexOf('Debugger listening on ws://') > -1 && output.indexOf('\n') > -1) {
const socketMatch = output.trim().match(/(ws:\/\/.+:[0-9]+\/.+?)\n/gm)
if (socketMatch && socketMatch[0]) {
child.stderr.removeListener('data', dataListener)
child.stdout.removeListener('data', dataListener)
const w = (webContents as any).create({}) as WebContents
w.loadURL('about:blank')
.then(() => w.executeJavaScript(`new Promise(resolve => {
@ -228,20 +271,24 @@ describe('node feature', () => {
.then(() => {
(w as any).destroy()
child.send('plz-quit')
success = true
cleanup()
done()
})
}
}
}
child.stderr.on('data', dataListener)
child.stdout.on('data', dataListener)
child.stderr.on('data', listener)
child.stdout.on('data', listener)
child.on('exit', () => {
if (!success) cleanup()
})
})
it('supports js binding', (done) => {
it('Supports js binding', (done) => {
child = childProcess.spawn(process.execPath, ['--inspect', path.join(fixtures, 'module', 'inspector-binding.js')], {
env: {
ELECTRON_RUN_AS_NODE: 'true'
},
env: { ELECTRON_RUN_AS_NODE: 'true' },
stdio: ['ipc']
}) as childProcess.ChildProcessWithoutNullStreams
exitPromise = emittedOnce(child, 'exit')
@ -256,7 +303,7 @@ describe('node feature', () => {
})
})
it('can find a module using a package.json main field', () => {
it('Can find a module using a package.json main field', () => {
const result = childProcess.spawnSync(process.execPath, [path.resolve(fixtures, 'api', 'electron-main-module', 'app.asar')])
expect(result.status).to.equal(0)
})