ssh2-sftp-client: 100% reproducible bug that results in node process crash when using promises (bug in promise reject)
Version: 9.0.4 Node: v18.12.0 OS: Mac OS 12.1
Problem manifests itself if network becomes inaccessible after Client.connect was already successfully executed but before Client.put method is called.
Code Snippet:
let Client = require('ssh2-sftp-client');
let sftp = new Client();
function sleep(ms) {
return new Promise((r) => setTimeout(r, ms));
}
async function run() {
const startTime = Date.now();
const filename = `random-file-name-${startTime}`;
const fileData = Buffer.from('TRACER FILE');
const remotePath = `incoming/${filename}`;
try {
console.log(`---- Before connect ----- `);
await sftp.connect({
host: '1.1.1.1',
port: 22,
username: 'user',
password: 'password',
});
console.log(`---- After connect ----- `);
console.log(`---- Sleep for 20s ----- `);
// !!!!!!! BREAK CONNECTION HERE while sleeping
await sleep(20000);
console.log(`---- Before put ----- `);
const result = await sftp.put(fileData, remotePath);
console.log(`---- After put ----- `);
console.log(`SFTP put result: ${result}`);
sftp.end();
} catch (err) {
console.error(`Error: ${err.message}`);
}
await sleep(7000);
console.log('The End');
}
run();
Log from the run that completes successfully:
---- Before connect -----
---- After connect -----
---- Sleep for 20s -----
---- Before put -----
---- After put -----
SFTP put result: Uploaded data stream to incoming/random-file-name-1670562812521
The End
Log from the run that crashes with disconnect during sleep(20000):
---- After connect -----
---- Sleep for 20s -----
---- Before put -----
/project/node_modules/ssh2-sftp-client/src/utils.js:25
throw newError;
^
Error: put: read ETIMEDOUT
at Client.fn (/project/node_modules/ssh2-sftp-client/src/utils.js:20:22)
at Client.emit (node:events:525:35)
at Socket.<anonymous> (/project/node_modules/ssh2/lib/client.js:745:12)
at Socket.emit (node:events:513:28)
at emitErrorNT (node:internal/streams/destroy:151:8)
at emitErrorCloseNT (node:internal/streams/destroy:116:3)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
code: 'ETIMEDOUT'
}
Node.js v18.12.0
It looks that for some reason in this use-case errorListener method in utils.js is invoked with reject parameter set to undefined resulting in exception vs promise reject.
How to break connection for MacOS:
# PF should be started: sudo pfctl -E
# Check current ruleset: sudo pfctl -sr
# To Apply this ruleset file: sudo pfctl -f ./pf-block-ip.conf
# To Flush (all) rulesets: sudo pfctl -F rules
# Block incoming traffic from some IP
block in quick from 1.1.1.1
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 24 (10 by maintainers)
I"m not questioning the fact it crashes. However, I’m not sure your conclusion is correct. As I stated before, I won’t have time to look at this in any detail until after the new year.
If you can diagnose further or if you want to provide a PR, that would be great, otherwise, you will have to wait until I get to it.