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 Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
parent
ba74e42000
commit
3ef1512f9e
@ -774,6 +774,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
|
(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.
|
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:
|
Node.js options that are allowed are:
|
||||||
- `--diagnostic-report-directory`
|
- `--diagnostic-report-directory`
|
||||||
- `--diagnostic-report-filename`
|
- `--diagnostic-report-filename`
|
||||||
|
46
src/node.cc
46
src/node.cc
@ -671,11 +671,49 @@ int InitializeNodeWithArgs(std::vector<std::string>* argv,
|
|||||||
|
|
||||||
#if !defined(NODE_WITHOUT_NODE_OPTIONS)
|
#if !defined(NODE_WITHOUT_NODE_OPTIONS)
|
||||||
std::string node_options;
|
std::string node_options;
|
||||||
|
|
||||||
if (credentials::SafeGetenv("NODE_OPTIONS", &node_options)) {
|
if (credentials::SafeGetenv("NODE_OPTIONS", &node_options)) {
|
||||||
// [0] is expected to be the program name, fill it in from the real argv
|
std::vector<std::string> env_argv;
|
||||||
// and use 'x' as a placeholder while parsing.
|
// [0] is expected to be the program name, fill it in from the real argv.
|
||||||
std::vector<std::string> env_argv = SplitString("x " + node_options, ' ');
|
env_argv.push_back(argv->at(0));
|
||||||
env_argv[0] = argv->at(0);
|
|
||||||
|
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()) {
|
||||||
|
errors->push_back("invalid value for NODE_OPTIONS "
|
||||||
|
"(invalid escape)\n");
|
||||||
|
return 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) {
|
||||||
|
errors->push_back("invalid value for NODE_OPTIONS "
|
||||||
|
"(unterminated string)\n");
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
|
||||||
const int exit_code = ProcessGlobalArgs(&env_argv, nullptr, errors, true);
|
const int exit_code = ProcessGlobalArgs(&env_argv, nullptr, errors, true);
|
||||||
if (exit_code != 0) return exit_code;
|
if (exit_code != 0) return exit_code;
|
||||||
|
1
test/fixtures/print A.js
vendored
Normal file
1
test/fixtures/print A.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
console.log('A')
|
@ -12,7 +12,12 @@ const tmpdir = require('../common/tmpdir');
|
|||||||
tmpdir.refresh();
|
tmpdir.refresh();
|
||||||
|
|
||||||
const printA = require.resolve('../fixtures/printA.js');
|
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 ${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(`-r ${printA} -r ${printA}`, 'A\nB\n');
|
||||||
expect(` -r ${printA} -r ${printA}`, 'A\nB\n');
|
expect(` -r ${printA} -r ${printA}`, 'A\nB\n');
|
||||||
expect(` --require ${printA} --require ${printA}`, 'A\nB\n');
|
expect(` --require ${printA} --require ${printA}`, 'A\nB\n');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user