Skip to content

Commit 058730d

Browse files
committed
src: validate node.config.json before parsing
1 parent d3bfd50 commit 058730d

2 files changed

Lines changed: 12 additions & 42 deletions

File tree

src/node_config_file.cc

Lines changed: 8 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -236,33 +236,6 @@ ParseResult ConfigReader::ParseConfig(const std::string_view& config_path) {
236236
return ParseResult::FileError;
237237
}
238238

239-
// Parse the configuration file
240-
simdjson::ondemand::parser json_parser;
241-
simdjson::ondemand::document document;
242-
if (json_parser.iterate(file_content).get(document)) {
243-
FPrintF(stderr, "Can't parse %s\n", config_path.data());
244-
return ParseResult::InvalidContent;
245-
}
246-
247-
// Validate config is an object
248-
simdjson::ondemand::object main_object;
249-
auto root_error = document.get_object().get(main_object);
250-
if (root_error) {
251-
if (root_error == simdjson::error_code::INCORRECT_TYPE) {
252-
FPrintF(stderr,
253-
"Root value unexpected not an object for %s\n\n",
254-
config_path.data());
255-
} else {
256-
FPrintF(stderr, "Can't parse %s\n", config_path.data());
257-
}
258-
return ParseResult::InvalidContent;
259-
}
260-
261-
// Validate against JSON Schema after basic parsing succeeds. This catches
262-
// unknown namespaces and type errors in properties before the option parsing
263-
// loop, which would otherwise produce less clear messages (or silently skip
264-
// unknown top-level keys). kNodeConfigSchema is a compile-time constant, so
265-
// compile it once on first call.
266239
{
267240
static const ata::schema_ref compiled_schema =
268241
ata::compile(kNodeConfigSchema);
@@ -280,6 +253,12 @@ ParseResult ConfigReader::ParseConfig(const std::string_view& config_path) {
280253
}
281254
}
282255

256+
simdjson::ondemand::parser json_parser;
257+
simdjson::ondemand::document document;
258+
CHECK_EQ(json_parser.iterate(file_content).get(document), simdjson::SUCCESS);
259+
simdjson::ondemand::object main_object;
260+
CHECK_EQ(document.get_object().get(main_object), simdjson::SUCCESS);
261+
283262
// Get all available namespaces for validation
284263
std::vector<std::string> available_namespaces =
285264
options_parser::MapAvailableNamespaces();
@@ -329,18 +308,9 @@ ParseResult ConfigReader::ParseConfig(const std::string_view& config_path) {
329308
}
330309
}
331310

332-
// Get the namespace object
333311
simdjson::ondemand::object namespace_object;
334-
auto field_error = field.value().get_object().get(namespace_object);
335-
336-
// If namespace value is not an object
337-
if (field_error) {
338-
FPrintF(stderr,
339-
"\"%s\" value unexpected for %s (should be an object)\n",
340-
namespace_name,
341-
config_path.data());
342-
return ParseResult::InvalidContent;
343-
}
312+
CHECK_EQ(field.value().get_object().get(namespace_object),
313+
simdjson::SUCCESS);
344314

345315
// Process options for this namespace using the unified method
346316
ParseResult result =

test/parallel/test-config-file.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ test('should handle empty json', async () => {
3838
`--experimental-config-file=${fixtures.path('rc/empty.json')}`,
3939
'-p', '"Hello, World!"',
4040
]);
41-
assert.match(result.stderr, /Can't parse/);
41+
assert.match(result.stderr, /invalid JSON document/);
4242
assert.match(result.stderr, /empty\.json: invalid content/);
4343
assert.strictEqual(result.stdout, '');
4444
assert.strictEqual(result.code, 9);
@@ -291,7 +291,7 @@ test('non object root', async () => {
291291
`--experimental-config-file=${fixtures.path('rc/non-object-root.json')}`,
292292
'-p', '"Hello, World!"',
293293
]);
294-
assert.match(result.stderr, /Root value unexpected not an object for/);
294+
assert.match(result.stderr, /\/: expected type object, got array/);
295295
assert.strictEqual(result.stdout, '');
296296
assert.strictEqual(result.code, 9);
297297
});
@@ -313,7 +313,7 @@ test('should throw correct error when a json is broken', async () => {
313313
`--experimental-config-file=${fixtures.path('rc/broken.json')}`,
314314
'-p', '"Hello, World!"',
315315
]);
316-
assert.match(result.stderr, /Can't parse/);
316+
assert.match(result.stderr, /invalid JSON document/);
317317
assert.match(result.stderr, /broken\.json: invalid content/);
318318
assert.strictEqual(result.stdout, '');
319319
assert.strictEqual(result.code, 9);
@@ -325,7 +325,7 @@ test('broken value in node_options', async () => {
325325
`--experimental-config-file=${fixtures.path('rc/broken-node-options.json')}`,
326326
'-p', '"Hello, World!"',
327327
]);
328-
assert.match(result.stderr, /Can't parse/);
328+
assert.match(result.stderr, /invalid JSON document/);
329329
assert.match(result.stderr, /broken-node-options\.json: invalid content/);
330330
assert.strictEqual(result.stdout, '');
331331
assert.strictEqual(result.code, 9);

0 commit comments

Comments
 (0)