Skip to content

Commit ff0ffe4

Browse files
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
1 parent d1f8ccb commit ff0ffe4

File tree

3 files changed

+51
-5
lines changed

3 files changed

+51
-5
lines changed

src/node_dotenv.cc

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,28 @@ Local<Object> Dotenv::ToObject(Environment* env) const {
107107

108108
std::string_view trim_spaces(std::string_view input) {
109109
if (input.empty()) return "";
110-
if (input.front() == ' ') {
111-
input.remove_prefix(input.find_first_not_of(' '));
110+
111+
size_t input_size = input.size();
112+
113+
size_t pos_start = 0;
114+
while (pos_start < input_size) {
115+
const char ch = input.at(pos_start);
116+
if (ch != ' ' && ch != '\t' && ch != '\n') {
117+
break;
118+
};
119+
pos_start++;
112120
}
113-
if (!input.empty() && input.back() == ' ') {
114-
input = input.substr(0, input.find_last_not_of(' ') + 1);
121+
122+
size_t pos_end = input_size - 1;
123+
while (pos_end > pos_start) {
124+
const char ch = input.at(pos_end);
125+
if (ch != ' ' && ch != '\t' && ch != '\n') {
126+
break;
127+
};
128+
pos_end--;
115129
}
116-
return input;
130+
131+
return input.substr(pos_start, pos_end - pos_start + 1);
117132
}
118133

119134
void Dotenv::ParseContent(const std::string_view input) {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
EMPTY_LINE='value after an empty line'
3+
4+
SPACES_LINE='value after a line with just some spaces'
5+
6+
TABS_LINE='value after a line with just some tabs'
7+
8+
SPACES_TABS_LINE='value after a line with just some spaces and tabs'

test/parallel/test-dotenv-edge-cases.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,29 @@ describe('.env supports edge cases', () => {
137137
assert.strictEqual(child.code, 0);
138138
});
139139

140+
it('lines containing only spaces (and tabs) should not effect values defined in the next lines', async () => {
141+
// Ref: https://github.com/nodejs/node/issues/56686
142+
const code = `
143+
process.loadEnvFile('./lines-with-only-spaces.env');
144+
console.log(\`EMPTY_LINE: "\${process.env.EMPTY_LINE}"\`);
145+
console.log(\`SPACES_LINE: "\${process.env.SPACES_LINE}"\`);
146+
console.log(\`TABS_LINE: "\${process.env.TABS_LINE}"\`);
147+
console.log(\`SPACES_TABS_LINE: "\${process.env.SPACES_TABS_LINE}"\`);
148+
`.trim();
149+
const child = await common.spawnPromisified(
150+
process.execPath,
151+
[ '--eval', code ],
152+
{ cwd: fixtures.path('dotenv') },
153+
);
154+
const lines = child.stdout.toString().split('\n').filter(Boolean);
155+
assert.deepStrictEqual(lines, [
156+
'EMPTY_LINE: "value after an empty line"',
157+
'SPACES_LINE: "value after a line with just some spaces"',
158+
'TABS_LINE: "value after a line with just some tabs"',
159+
'SPACES_TABS_LINE: "value after a line with just some spaces and tabs"',
160+
]);
161+
});
162+
140163
it('should handle when --env-file is passed along with --', async () => {
141164
const child = await common.spawnPromisified(
142165
process.execPath,

0 commit comments

Comments
 (0)