src: improve node::Dotenv trimming

the trimming functionality that the dotenv parsing uses currently
only takes into consideration plain spaces (' '), other type of
space characters such as tabs and newlines are not trimmed, this
can cause subtle bugs, so the changes here make sure that such
characters get trimmed as well

Co-authored-by: Yagiz Nizipli <yagiz@nizipli.com>
PR-URL: https://github.com/nodejs/node/pull/56983
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Dario Piotrowicz 2025-02-11 22:26:51 +00:00 committed by GitHub
parent cbedcd1696
commit 43ffcf1d2e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 46 additions and 5 deletions

View File

@ -105,15 +105,22 @@ Local<Object> Dotenv::ToObject(Environment* env) const {
return result;
}
// Removes space characters (spaces, tabs and newlines) from
// the start and end of a given input string
std::string_view trim_spaces(std::string_view input) {
if (input.empty()) return "";
if (input.front() == ' ') {
input.remove_prefix(input.find_first_not_of(' '));
auto pos_start = input.find_first_not_of(" \t\n");
if (pos_start == std::string_view::npos) {
return "";
}
if (!input.empty() && input.back() == ' ') {
input = input.substr(0, input.find_last_not_of(' ') + 1);
auto pos_end = input.find_last_not_of(" \t\n");
if (pos_end == std::string_view::npos) {
return input.substr(pos_start);
}
return input;
return input.substr(pos_start, pos_end - pos_start + 1);
}
void Dotenv::ParseContent(const std::string_view input) {
@ -147,6 +154,13 @@ void Dotenv::ParseContent(const std::string_view input) {
key = content.substr(0, equal);
content.remove_prefix(equal + 1);
key = trim_spaces(key);
// If the value is not present (e.g. KEY=) set is to an empty string
if (content.front() == '\n') {
store_.insert_or_assign(std::string(key), "");
continue;
}
content = trim_spaces(content);
if (key.empty()) {

View File

@ -0,0 +1,8 @@
EMPTY_LINE='value after an empty line'
SPACES_LINE='value after a line with just some spaces'
TABS_LINE='value after a line with just some tabs'
SPACES_TABS_LINE='value after a line with just some spaces and tabs'

View File

@ -137,6 +137,25 @@ describe('.env supports edge cases', () => {
assert.strictEqual(child.code, 0);
});
it('should handle lines that come after lines with only spaces (and tabs)', async () => {
// Ref: https://github.com/nodejs/node/issues/56686
const code = `
process.loadEnvFile('./lines-with-only-spaces.env');
assert.strictEqual(process.env.EMPTY_LINE, 'value after an empty line');
assert.strictEqual(process.env.SPACES_LINE, 'value after a line with just some spaces');
assert.strictEqual(process.env.TABS_LINE, 'value after a line with just some tabs');
assert.strictEqual(process.env.SPACES_TABS_LINE, 'value after a line with just some spaces and tabs');
`.trim();
const child = await common.spawnPromisified(
process.execPath,
[ '--eval', code ],
{ cwd: fixtures.path('dotenv') },
);
assert.strictEqual(child.stdout, '');
assert.strictEqual(child.stderr, '');
assert.strictEqual(child.code, 0);
});
it('should handle when --env-file is passed along with --', async () => {
const child = await common.spawnPromisified(
process.execPath,