diff --git a/lib/child_process.js b/lib/child_process.js index 5c853716a26a4e..4cf14e435bb95c 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -46,6 +46,7 @@ const { SymbolDispose, } = primordials; + const { convertToValidSignal, getSystemErrorName, @@ -53,6 +54,7 @@ const { promisify, } = require('internal/util'); const { isArrayBufferView } = require('internal/util/types'); +const { isWindows } = require('internal/util/platform'); let debug = require('internal/util/debuglog').debuglog( 'child_process', (fn) => { @@ -88,7 +90,7 @@ const child_process = require('internal/child_process'); const { getValidStdio, setupChannel, - ChildProcess, + ChildProcess: OriginalChildProcess, stdioStringToArray, } = child_process; @@ -97,6 +99,65 @@ const MAX_BUFFER = 1024 * 1024; const isZOS = process.platform === 'os390'; let addAbortListener; +// Enhanced ChildProcess class with Windows encoding support +class ChildProcess extends OriginalChildProcess { + constructor(options) { + super(options); + this._stdinEncodingReady = false; + this._stdinQueue = []; + this._windowsShellEncoding = null; + } + + _handleEncodingSync() { + const handleReady = () => { + this._stdinEncodingReady = true; + this._stdinQueue.forEach(({ data, encoding, callback }) => { + this._writeStdin(data, encoding, callback); + }); + this._stdinQueue = []; + }; + + // Force UTF-8 mode immediately + this._writeStdin('chcp 65001 > nul\r\n', null, () => { + this._windowsShellEncoding = 'utf8'; + handleReady(); + }); + } + + _writeStdin(data, encoding, callback) { + if (!this._stdinEncodingReady && this._windowsShellEncoding) { + this._stdinQueue.push({ data, encoding, callback }); + return true; + } + + if (encoding && this._windowsShellEncoding === 'utf8') { + try { + if (typeof data === 'string') { + data = Buffer.from(data, encoding); + } else if (Buffer.isBuffer(data)) { + data = Buffer.from(data.toString(), encoding); + } + } catch (err) { + process.nextTick(() => this.emit('error', err)); + return false; + } + } + + return this.stdin.write(data, callback); + } + + spawn(options) { + if (isWindows && + options.file.toLowerCase().endsWith('cmd.exe') && + process.env.NODE_CHILD_PROCESS_NO_ENCODING_SYNC !== '1') { + this._windowsShellEncoding = 'gbk'; + this._handleEncodingSync(); + } + + return super.spawn(options); + } +} + /** * Spawns a new Node.js process + fork. * @param {string|URL} modulePath @@ -1020,3 +1081,4 @@ module.exports = { spawn, spawnSync, }; + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000000000..c8060d3c654326 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,30 @@ +{ + "name": "node", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "iconv-lite": "^0.6.3" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000000000..eb76e373497632 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "iconv-lite": "^0.6.3" + } +} diff --git a/test-fix.js b/test-fix.js new file mode 100644 index 00000000000000..517376cb93d0ef --- /dev/null +++ b/test-fix.js @@ -0,0 +1,31 @@ +// Testing for issue 57780, works on MacOS and Windows,link here: +// https://github.com/nodejs/node/issues/57780 + +const child_process = require('child_process'); +const iconv = require('iconv-lite'); // Still needed for Windows testing + +const isWindows = process.platform === 'win32'; + +async function amain() { + if (isWindows) { + // Windows: Test cmd.exe with UTF-8 + GBK + const cp = child_process.spawn('cmd', [], { + stdio: ['pipe', 'inherit', 'inherit'], + env: { ...process.env, CHCP: '65001' } // Force UTF-8 + }); + + const utf8Cmd = 'echo utf8中文测试\r\n'; + const gbkCmd = iconv.encode('echo gbk中文测试\r\n', 'gbk'); + + cp.stdin.write(utf8Cmd); + cp.stdin.write(gbkCmd); + cp.stdin.end(); + } else { + // macOS: Test UTF-8 in bash + console.log('Testing UTF-8 on macOS:'); + const bash = child_process.spawn('bash', ['-c', 'echo "macOS中文测试"']); + bash.stdout.pipe(process.stdout); + } +} + +amain().catch(console.error); \ No newline at end of file