summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaƫl Nison <mael@fb.com>2018-11-03 10:52:44 -0700
committerRichard Lau <rlau@redhat.com>2020-10-07 06:18:30 -0400
commit2eb627301c1f6681ec51f43b84e37f3908514853 (patch)
treef63ceb527c63cc4faf6e260925138d7974d55e04
parent356442462551e4400c4617c6d0a1f721c78957c0 (diff)
downloadnode-new-2eb627301c1f6681ec51f43b84e37f3908514853.tar.gz
src: allows escaping NODE_OPTIONS with backslashes
The characters specified within NODE_OPTIONS can now be escaped, which is handy especially in conjunction with `--require` (where the file path might happen to contain spaces that shouldn't cause the option to be split into two). Fixes: https://github.com/nodejs/node/issues/12971 PR-URL: https://github.com/nodejs/node/pull/24065 Backport-PR-URL: https://github.com/nodejs/node/pull/35342 Reviewed-By: Anna Henningsen <anna@addaleax.net> Refs: https://github.com/microsoft/vscode-js-debug/issues/769
-rw-r--r--doc/api/cli.md7
-rw-r--r--src/node.cc50
-rw-r--r--test/fixtures/print A.js1
-rw-r--r--test/parallel/test-cli-node-options.js5
4 files changed, 51 insertions, 12 deletions
diff --git a/doc/api/cli.md b/doc/api/cli.md
index a121cbea75..c896f4e6e0 100644
--- a/doc/api/cli.md
+++ b/doc/api/cli.md
@@ -642,6 +642,13 @@ if they had been specified on the command line before the actual command line
(so they can be overridden). Node.js will exit with an error if an option
that is not allowed in the environment is used, such as `-p` or a script file.
+In case an option value happens to contain a space (for example a path listed in
+`--require`), it must be escaped using double quotes. For example:
+
+```bash
+--require "./my path/file.js"
+```
+
Node.js options that are allowed are:
- `--enable-fips`
- `--experimental-modules`
diff --git a/src/node.cc b/src/node.cc
index 7c0118758d..58bd3e22f2 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -2610,23 +2610,49 @@ void Init(std::vector<std::string>* argv,
#if !defined(NODE_WITHOUT_NODE_OPTIONS)
std::string node_options;
+
if (SafeGetenv("NODE_OPTIONS", &node_options)) {
std::vector<std::string> env_argv;
// [0] is expected to be the program name, fill it in from the real argv.
env_argv.push_back(argv->at(0));
- // Split NODE_OPTIONS at each ' ' character.
- std::string::size_type index = std::string::npos;
- do {
- std::string::size_type prev_index = index;
- index = node_options.find(' ', index + 1);
- if (index - prev_index == 1) continue;
-
- const std::string option = node_options.substr(
- prev_index + 1, index - prev_index - 1);
- if (!option.empty())
- env_argv.emplace_back(std::move(option));
- } while (index != std::string::npos);
+ bool is_in_string = false;
+ bool will_start_new_arg = true;
+ for (std::string::size_type index = 0;
+ index < node_options.size();
+ ++index) {
+ char c = node_options.at(index);
+
+ // Backslashes escape the following character
+ if (c == '\\' && is_in_string) {
+ if (index + 1 == node_options.size()) {
+ fprintf(stderr, "invalid value for NODE_OPTIONS "
+ "(invalid escape)\n");
+ exit(9);
+ } else {
+ c = node_options.at(++index);
+ }
+ } else if (c == ' ' && !is_in_string) {
+ will_start_new_arg = true;
+ continue;
+ } else if (c == '"') {
+ is_in_string = !is_in_string;
+ continue;
+ }
+
+ if (will_start_new_arg) {
+ env_argv.push_back(std::string(1, c));
+ will_start_new_arg = false;
+ } else {
+ env_argv.back() += c;
+ }
+ }
+
+ if (is_in_string) {
+ fprintf(stderr, "invalid value for NODE_OPTIONS "
+ "(unterminated string)\n");
+ exit(9);
+ }
ProcessArgv(&env_argv, nullptr, true);
diff --git a/test/fixtures/print A.js b/test/fixtures/print A.js
new file mode 100644
index 0000000000..30a56425de
--- /dev/null
+++ b/test/fixtures/print A.js
@@ -0,0 +1 @@
+console.log('A')
diff --git a/test/parallel/test-cli-node-options.js b/test/parallel/test-cli-node-options.js
index 3e1d6808c8..fe4845ce11 100644
--- a/test/parallel/test-cli-node-options.js
+++ b/test/parallel/test-cli-node-options.js
@@ -15,7 +15,12 @@ tmpdir.refresh();
process.chdir(tmpdir.path);
const printA = require.resolve('../fixtures/printA.js');
+const printSpaceA = require.resolve('../fixtures/print A.js');
+
+expect(` -r ${printA} `, 'A\nB\n');
expect(`-r ${printA}`, 'A\nB\n');
+expect(`-r ${JSON.stringify(printA)}`, 'A\nB\n');
+expect(`-r ${JSON.stringify(printSpaceA)}`, 'A\nB\n');
expect(`-r ${printA} -r ${printA}`, 'A\nB\n');
expect('--no-deprecation', 'B\n');
expect('--no-warnings', 'B\n');