Skip to content

Commit 9b1f9af

Browse files
committed
Handle error when attempting simultaneous PASV requests. Fixes #90.
1 parent 513245c commit 9b1f9af

File tree

3 files changed

+56
-23
lines changed

3 files changed

+56
-23
lines changed

lib/jsftp.js

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -112,19 +112,15 @@ Ftp.prototype.reemit = function(event) {
112112
};
113113

114114
Ftp.prototype._createSocket = function(port, host, firstAction) {
115-
if (this.socket && this.socket.destroy) this.socket.destroy();
115+
if (this.socket && this.socket.destroy) {
116+
this.socket.destroy();
117+
}
116118

117119
this.authenticated = false;
118120
var socket = Net.createConnection(port, host, firstAction || NOOP);
119121
socket.on('connect', this.reemit('connect'));
120122
socket.on('timeout', this.reemit('timeout'));
121123

122-
this._createStreams(socket);
123-
124-
return socket;
125-
};
126-
127-
Ftp.prototype._createStreams = function(socket) {
128124
this.pipeline = es.pipeline(socket, this.resParser);
129125

130126
var self = this;
@@ -133,6 +129,8 @@ Ftp.prototype._createStreams = function(socket) {
133129
self.parseResponse.call(self, data);
134130
});
135131
this.pipeline.on('error', this.reemit('error'));
132+
133+
return socket;
136134
};
137135

138136
Ftp.prototype.parseResponse = function(data) {
@@ -198,31 +196,28 @@ Ftp.prototype.nextCmd = function() {
198196
* @param {function} callback
199197
*/
200198
Ftp.prototype.execute = function(action, callback) {
201-
if (!callback) callback = NOOP;
202-
203199
if (this.socket && this.socket.writable) {
204-
return this.runCommand(action, callback);
200+
return this.runCommand(action, callback || NOOP);
205201
}
206202

207203
var self = this;
208204
this.authenticated = false;
209205
this.socket = this._createSocket(this.port, this.host, function() {
210-
self.runCommand(action, callback);
206+
self.runCommand(action, callback || NOOP);
211207
});
212208
};
213209

214210
Ftp.prototype.runCommand = function(action, callback) {
215-
var self = this;
216-
217-
function executeCmd() {
218-
self.cmdBuffer_.push([action, callback]);
219-
self.nextCmd();
220-
}
211+
var executeCmd = (function _executeCmd() {
212+
this.cmdBuffer_.push([action, callback]);
213+
this.nextCmd();
214+
}).bind(this);
221215

222-
if (self.authenticated || /feat|syst|user|pass/.test(action)) {
216+
if (this.authenticated || /feat|syst|user|pass/.test(action)) {
223217
return executeCmd();
224218
}
225219

220+
var self = this;
226221
this.getFeatures(function() {
227222
self.auth(self.user, self.pass, executeCmd);
228223
});
@@ -425,6 +420,11 @@ Ftp.prototype.get = function(remotePath, localPath, callback) {
425420
return callback(err);
426421
}
427422

423+
if (!socket) {
424+
return callback(new Error(
425+
'An unknown error occurred when trying to retrieve PASV socket'));
426+
}
427+
428428
var writeStream = fs.createWriteStream(localPath);
429429
writeStream.on('error', callback);
430430

@@ -584,6 +584,12 @@ Ftp.prototype.getPasvSocket = function(callback) {
584584

585585
var socket = Net.createConnection(res.port, res.host);
586586
socket.setTimeout(timeout || TIMEOUT);
587+
socket.on('error', function(err) {
588+
if (err.code === 'ECONNREFUSED') {
589+
err.msg = 'Probably trying a PASV operation while one is in progress';
590+
}
591+
callback(err);
592+
});
587593
callback(null, socket);
588594
});
589595
});
@@ -635,7 +641,7 @@ Ftp.prototype.ls = function(filePath, callback) {
635641
// and we set the variable `useList` to true, to avoid extra round
636642
// trips to the server to check.
637643
if ((err && (err.code === 502 || err.code === 500)) ||
638-
(self.system && self.system.indexOf('hummingbird') > -1))
644+
(self.system && self.system.indexOf('hummingbird') > -1))
639645
// Not sure if the 'hummingbird' system check ^^^ is still
640646
// necessary. If they support any standards, the 500 error
641647
// should have us covered. Let's leave it for now.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "jsftp",
33
"id": "jsftp",
4-
"version": "1.3.6",
4+
"version": "1.3.7",
55
"description": "A sane FTP client implementation for NodeJS",
66
"keywords": [ "ftp", "protocol", "files", "server", "client", "async" ],
77
"author": "Sergi Mansilla <sergi.mansilla@gmail.com> (http://sergimansilla.com)",

test/jsftp_test.js

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ var rimraf = require("rimraf");
2020

2121
var concat = function(bufs) {
2222
var buffer, length = 0,
23-
index = 0;
23+
index = 0;
2424

2525
if (!Array.isArray(bufs))
2626
bufs = Array.prototype.slice.call(arguments);
@@ -83,6 +83,7 @@ describe("jsftp test suite", function() {
8383
rimraf(getLocalPath(''), function() {
8484
Fs.mkdirSync(getLocalPath(''));
8585
Fs.writeFileSync(getLocalPath('testfile.txt'), "test");
86+
Fs.writeFileSync(getLocalPath('testfile2.txt'), "test2");
8687

8788
if (FTPCredentials.host === "localhost") {
8889
server = new ftpServer();
@@ -226,7 +227,7 @@ describe("jsftp test suite", function() {
226227
assert.equal(err.code, 530);
227228
assert.equal(data, null);
228229
next();
229-
});
230+
});
230231
});
231232

232233
it("test invalid password", function(next) {
@@ -238,7 +239,7 @@ describe("jsftp test suite", function() {
238239
assert.equal(err.code, 530);
239240
assert.equal(data, null);
240241
next();
241-
});
242+
});
242243
});
243244

244245
it("test getFeatures", function(next) {
@@ -767,4 +768,30 @@ describe("jsftp test suite", function() {
767768
next();
768769
});
769770
});
771+
772+
it("Test handling error on simultaneous PASV requests {#90}", function(next) {
773+
var file1 = remoteCWD + "/testfile.txt";
774+
var file2 = remoteCWD + "/testfile2.txt";
775+
776+
var counter = 0;
777+
var args = [];
778+
function onDone() {
779+
counter += 1;
780+
if (counter === 2) {
781+
assert.ok(args.some(function(arg) {
782+
return arg && arg.code === 'ECONNREFUSED' && arg.msg ===
783+
'Probably trying a PASV operation while one is in progress';
784+
}));
785+
next();
786+
}
787+
}
788+
789+
function pushit() {
790+
args.push(arguments[0]);
791+
onDone();
792+
}
793+
794+
ftp.get(file1, pushit);
795+
ftp.get(file2, pushit);
796+
});
770797
});

0 commit comments

Comments
 (0)