From d7aaae1c1129d8e6deeb40dd2d1a17ae783fde50 Mon Sep 17 00:00:00 2001 From: LiviaMedeiros Date: Mon, 7 Aug 2023 02:27:14 +0800 Subject: [PATCH] squash: strict validation, test for bad input --- lib/child_process.js | 1 + test/parallel/test-child-process-urlfile.mjs | 105 ++++++++++++++----- 2 files changed, 81 insertions(+), 25 deletions(-) diff --git a/lib/child_process.js b/lib/child_process.js index 27bec285f8bbe0..10bcaacc3a9f06 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -546,6 +546,7 @@ function copyProcessEnvToEnv(env, name, optionEnv) { function normalizeSpawnArguments(file, args, options) { file = getValidatedPath(file, 'file'); + validateString(file, 'file'); if (file.length === 0) throw new ERR_INVALID_ARG_VALUE('file', file, 'cannot be empty'); diff --git a/test/parallel/test-child-process-urlfile.mjs b/test/parallel/test-child-process-urlfile.mjs index f0dee47f4a3630..4bd56b397a0e8f 100644 --- a/test/parallel/test-child-process-urlfile.mjs +++ b/test/parallel/test-child-process-urlfile.mjs @@ -1,42 +1,97 @@ import { isWindows, mustCall, mustSucceed, mustNotCall } from '../common/index.mjs'; -import { strictEqual } from 'node:assert'; -import { pathToFileURL } from 'node:url'; +import { strictEqual, throws } from 'node:assert'; import cp from 'node:child_process'; +import url from 'node:url'; import tmpdir from '../common/tmpdir.js'; tmpdir.refresh(); const cwd = tmpdir.path; +const cwdUrl = url.pathToFileURL(cwd); const whichCommand = isWindows ? 'where.exe cmd.exe' : 'which pwd'; const pwdFullPath = `${cp.execSync(whichCommand)}`.trim(); -const pwdUrl = pathToFileURL(pwdFullPath); -const pwdCommandAndOptions = isWindows ? - [pwdUrl, ['/d', '/c', 'cd'], { cwd: pathToFileURL(cwd) }] : - [pwdUrl, [], { cwd: pathToFileURL(cwd) }]; +const pwdWHATWGUrl = url.pathToFileURL(pwdFullPath); -{ - cp.execFile(...pwdCommandAndOptions, mustSucceed((stdout) => { +// Test for WHATWG URL instance, legacy URL, and URL-like object +for (const pwdUrl of [ + pwdWHATWGUrl, + new url.URL(pwdWHATWGUrl), + { + href: pwdWHATWGUrl.href, + origin: pwdWHATWGUrl.origin, + protocol: pwdWHATWGUrl.protocol, + username: pwdWHATWGUrl.username, + password: pwdWHATWGUrl.password, + host: pwdWHATWGUrl.host, + hostname: pwdWHATWGUrl.hostname, + port: pwdWHATWGUrl.port, + pathname: pwdWHATWGUrl.pathname, + search: pwdWHATWGUrl.search, + searchParams: new URLSearchParams(pwdWHATWGUrl.searchParams), + hash: pwdWHATWGUrl.hash, + }, +]) { + const pwdCommandAndOptions = isWindows ? + [pwdUrl, ['/d', '/c', 'cd'], { cwd: cwdUrl }] : + [pwdUrl, [], { cwd: cwdUrl }]; + + { + cp.execFile(...pwdCommandAndOptions, mustSucceed((stdout) => { + strictEqual(`${stdout}`.trim(), cwd); + })); + } + + { + const stdout = cp.execFileSync(...pwdCommandAndOptions); strictEqual(`${stdout}`.trim(), cwd); - })); -} + } -{ - const stdout = cp.execFileSync(...pwdCommandAndOptions); - strictEqual(`${stdout}`.trim(), cwd); -} + { + const pwd = cp.spawn(...pwdCommandAndOptions); + pwd.stdout.on('data', mustCall((stdout) => { + strictEqual(`${stdout}`.trim(), cwd); + })); + pwd.stderr.on('data', mustNotCall()); + pwd.on('close', mustCall((code) => { + strictEqual(code, 0); + })); + } -{ - const pwd = cp.spawn(...pwdCommandAndOptions); - pwd.stdout.on('data', mustCall((stdout) => { + { + const stdout = cp.spawnSync(...pwdCommandAndOptions).stdout; strictEqual(`${stdout}`.trim(), cwd); - })); - pwd.stderr.on('data', mustNotCall()); - pwd.on('close', mustCall((code) => { - strictEqual(code, 0); - })); + } + } -{ - const stdout = cp.spawnSync(...pwdCommandAndOptions).stdout; - strictEqual(`${stdout}`.trim(), cwd); +// Test for non-URL objects +for (const badFile of [ + Buffer.from(pwdFullPath), + {}, + { href: pwdWHATWGUrl.href }, + { pathname: pwdWHATWGUrl.pathname }, +]) { + const pwdCommandAndOptions = isWindows ? + [badFile, ['/d', '/c', 'cd'], { cwd: cwdUrl }] : + [badFile, [], { cwd: cwdUrl }]; + + throws( + () => cp.execFile(...pwdCommandAndOptions, mustNotCall()), + { code: 'ERR_INVALID_ARG_TYPE' }, + ); + + throws( + () => cp.execFileSync(...pwdCommandAndOptions), + { code: 'ERR_INVALID_ARG_TYPE' }, + ); + + throws( + () => cp.spawn(...pwdCommandAndOptions), + { code: 'ERR_INVALID_ARG_TYPE' }, + ); + + throws( + () => cp.spawnSync(...pwdCommandAndOptions), + { code: 'ERR_INVALID_ARG_TYPE' }, + ); }