Comparing version 0.2.6 to 0.2.7
@@ -20,6 +20,6 @@ /* | ||
var FTPCredentials = { | ||
host: "", | ||
user: "", | ||
host: "CN20081656.p-client.net", | ||
user: "danielatest", | ||
port: 21, | ||
pass: "" | ||
pass: "test1324" | ||
}; | ||
@@ -75,8 +75,6 @@ | ||
}, | ||
/* | ||
">test features command": function(next) { | ||
"test features command": function(next) { | ||
var ftp = this.ftp; | ||
ftp.auth(FTPCredentials.user, FTPCredentials.pass, function(err, res) { | ||
assert.ok(!err); | ||
assert.ok(Array.isArray(ftp.features)); | ||
@@ -91,3 +89,2 @@ | ||
}, | ||
*/ | ||
@@ -109,14 +106,12 @@ "test initialize": function(next) { | ||
var ftp = this.ftp; | ||
ftp.auth(FTPCredentials.user, FTPCredentials.pass, function(err, res) { | ||
ftp.raw.pwd(function(err, res) { | ||
if (err) throw err; | ||
ftp.raw.pwd(function(err, res) { | ||
if (err) throw err; | ||
var code = parseInt(res.code, 10); | ||
assert.ok(code === 257, "PWD command was not successful"); | ||
var code = parseInt(res.code, 10); | ||
assert.ok(code === 257, "PWD command was not successful"); | ||
ftp.raw.quit(function(err, res) { | ||
if (err) throw err; | ||
ftp.raw.quit(function(err, res) { | ||
if (err) throw err; | ||
next(); | ||
}); | ||
next(); | ||
}); | ||
@@ -127,29 +122,24 @@ }); | ||
var ftp = this.ftp; | ||
ftp.auth(FTPCredentials.user, FTPCredentials.pass, function(err, res) { | ||
ftp.raw.cwd(remoteCWD, function(err, res) { | ||
if (err) throw err; | ||
ftp.raw.cwd(remoteCWD, function(err, res) { | ||
var code = parseInt(res.code, 10); | ||
assert.ok(code === 200 || code === 250, "CWD command was not successful"); | ||
ftp.raw.pwd(function(err, res) { | ||
if (err) throw err; | ||
var code = parseInt(res.code, 10); | ||
assert.ok(code === 200 || code === 250, "CWD command was not successful"); | ||
assert.ok(code === 257, "PWD command was not successful"); | ||
assert.ok(res.text.indexOf(remoteCWD), "Unexpected CWD"); | ||
}); | ||
ftp.raw.pwd(function(err, res) { | ||
if (err) throw err; | ||
var code = parseInt(res.code, 10); | ||
assert.ok(code === 257, "PWD command was not successful"); | ||
assert.ok(res.text.indexOf(remoteCWD), "Unexpected CWD"); | ||
}); | ||
ftp.raw.cwd("/unexistentDir/", function(err, res) { | ||
if (err) | ||
assert.ok(err); | ||
else { | ||
code = parseInt(res.code, 10); | ||
assert.ok(code === 550, "A (wrong) CWD command was successful. It should have failed"); | ||
} | ||
next(); | ||
}); | ||
ftp.raw.cwd("/unexistentDir/", function(err, res) { | ||
if (err) | ||
assert.ok(err); | ||
else { | ||
code = parseInt(res.code, 10); | ||
assert.ok(code === 550, "A (wrong) CWD command was successful. It should have failed"); | ||
} | ||
next(); | ||
}); | ||
@@ -159,10 +149,5 @@ }); | ||
"test passive listing of current directory": function(next) { | ||
var ftp = this.ftp; | ||
ftp.auth(FTPCredentials.user, FTPCredentials.pass, function(res) { | ||
ftp.list(remoteCWD, function(err, res){ | ||
assert.ok(!err, err); | ||
//assert.ok(res); | ||
next(); | ||
}); | ||
this.ftp.list(remoteCWD, function(err, res){ | ||
assert.ok(!err, err); | ||
next(); | ||
}); | ||
@@ -173,13 +158,11 @@ }, | ||
var ftp = this.ftp; | ||
ftp.auth(FTPCredentials.user, FTPCredentials.pass, function(err, res) { | ||
ftp.raw.pwd(function(err, res) { | ||
var parent = /.*"(.*)".*/.exec(res.text)[1]; | ||
var path = Path.resolve(parent + "/" + remoteCWD); | ||
ftp.raw.stat(path, function(err, res) { | ||
assert.ok(!err, res); | ||
assert.ok(res); | ||
ftp.raw.pwd(function(err, res) { | ||
var parent = /.*"(.*)".*/.exec(res.text)[1]; | ||
var path = Path.resolve(parent + "/" + remoteCWD); | ||
ftp.raw.stat(path, function(err, res) { | ||
assert.ok(!err, res); | ||
assert.ok(res); | ||
assert.ok(res.code === 211 || res.code === 212 || res.code === 213); | ||
next(); | ||
}); | ||
assert.ok(res.code === 211 || res.code === 212 || res.code === 213); | ||
next(); | ||
}); | ||
@@ -194,11 +177,9 @@ }); | ||
var ftp = this.ftp; | ||
ftp.auth(FTPCredentials.user, FTPCredentials.pass, function(err, res) { | ||
ftp.raw.mkd(newDir, function(err, res) { | ||
ftp.raw.mkd(newDir, function(err, res) { | ||
assert.ok(!err); | ||
assert.equal(res.code, 257); | ||
ftp.raw.rmd(newDir, function(err, res) { | ||
assert.ok(!err); | ||
assert.ok(res.code === 257); | ||
ftp.raw.rmd(newDir, function(err, res) { | ||
assert.ok(!err); | ||
next(); | ||
}); | ||
next(); | ||
}); | ||
@@ -213,11 +194,9 @@ }); | ||
var ftp = this.ftp; | ||
ftp.auth(FTPCredentials.user, FTPCredentials.pass, function(err, res) { | ||
ftp.raw.mkd(newDir, function(err, res) { | ||
ftp.raw.mkd(newDir, function(err, res) { | ||
assert.ok(!err); | ||
assert.equal(res.code, 257); | ||
ftp.raw.rmd(newDir, function(err, res) { | ||
assert.ok(!err); | ||
assert.ok(res.code === 257); | ||
ftp.raw.rmd(newDir, function(err, res) { | ||
assert.ok(!err); | ||
next(); | ||
}); | ||
next(); | ||
}); | ||
@@ -232,17 +211,15 @@ }); | ||
var ftp = this.ftp; | ||
ftp.auth(FTPCredentials.user, FTPCredentials.pass, function(err, res) { | ||
Fs.readFile(CWD + "/jsftp_test.js", "binary", function(err, data) { | ||
var buffer = new Buffer(data, "binary"); | ||
ftp.put(filePath, buffer, function(err, res) { | ||
assert.ok(!err, err); | ||
Fs.readFile(CWD + "/jsftp_test.js", "binary", function(err, data) { | ||
var buffer = new Buffer(data, "binary"); | ||
ftp.put(filePath, buffer, function(err, res) { | ||
assert.ok(!err, err); | ||
ftp.ls(filePath, function(err, res) { | ||
ftp.ls(filePath, function(err, res) { | ||
assert.ok(!err); | ||
assert.equal(buffer.length, Fs.statSync(CWD + "/jsftp_test.js").size); | ||
ftp.raw.dele(filePath, function(err, data) { | ||
assert.ok(!err); | ||
assert.equal(buffer.length, Fs.statSync(CWD + "/jsftp_test.js").size); | ||
ftp.raw.dele(filePath, function(err, data) { | ||
assert.ok(!err); | ||
next(); | ||
}); | ||
next(); | ||
}); | ||
@@ -260,18 +237,16 @@ }); | ||
var ftp = this.ftp; | ||
ftp.auth(FTPCredentials.user, FTPCredentials.pass, function(err, res) { | ||
Fs.readFile(CWD + "/jsftp_test.js", "binary", function(err, data) { | ||
var buffer = new Buffer(data, "binary"); | ||
ftp.put(from, buffer, function(err, res) { | ||
assert.ok(!err, err); | ||
Fs.readFile(CWD + "/jsftp_test.js", "binary", function(err, data) { | ||
var buffer = new Buffer(data, "binary"); | ||
ftp.put(from, buffer, function(err, res) { | ||
assert.ok(!err, err); | ||
ftp.rename(from, to, function(err, res) { | ||
ftp.ls(to, function(err, res) { | ||
assert.ok(!err); | ||
ftp.rename(from, to, function(err, res) { | ||
ftp.ls(to, function(err, res) { | ||
assert.ok(!err); | ||
assert.equal(buffer.length, Fs.statSync(CWD + "/jsftp_test.js").size); | ||
assert.equal(buffer.length, Fs.statSync(CWD + "/jsftp_test.js").size); | ||
ftp.raw.dele(to, function(err, data) { | ||
assert.ok(!err); | ||
next(); | ||
}); | ||
ftp.raw.dele(to, function(err, data) { | ||
assert.ok(!err); | ||
next(); | ||
}); | ||
@@ -288,17 +263,15 @@ }); | ||
var localPath = CWD + "/" + fileName; | ||
var remotePath = remoteCWD + "/" + fileName; | ||
var remotePath = remoteCWD + "/" + fileName + ".test"; | ||
ftp.auth(FTPCredentials.user, FTPCredentials.pass, function(err, res) { | ||
Fs.readFile(localPath, "binary", function(err, data) { | ||
var buffer = new Buffer(data, "binary"); | ||
ftp.put(remotePath, buffer, function(err, res) { | ||
Fs.readFile(localPath, "binary", function(err, data) { | ||
var buffer = new Buffer(data, "binary"); | ||
ftp.put(remotePath, buffer, function(err, res) { | ||
assert.ok(!err, err); | ||
ftp.get(remotePath, function(err, data) { | ||
assert.ok(!err, err); | ||
ftp.get(remotePath, function(err, data) { | ||
assert.ok(!err, err); | ||
assert.equal(buffer.length, data.length); | ||
ftp.raw.dele(remotePath, function(err, data) { | ||
assert.ok(!err); | ||
next(); | ||
}); | ||
assert.equal(buffer.length, data.length); | ||
ftp.raw.dele(remotePath, function(err, data) { | ||
assert.ok(!err); | ||
next(); | ||
}); | ||
@@ -315,20 +288,17 @@ }); | ||
ftp.auth(FTPCredentials.user, FTPCredentials.pass, function(err, res) { | ||
ftp.put(filePath, new Buffer("test"), handler); | ||
ftp.get(filePath, function(err, data) { | ||
assert.ok(!err, err); | ||
assert.ok(data); | ||
}); | ||
ftp.put(filePath, new Buffer("test"), handler); | ||
ftp.get(filePath, function(err, data) { | ||
assert.ok(!err, err); | ||
assert.ok(data); | ||
}); | ||
ftp.put(filePath, new Buffer("test"), handler); | ||
ftp.get(filePath, function(err, data) { | ||
assert.ok(!err, err); | ||
assert.ok(data); | ||
assert.equal(counter, 2); | ||
next(); | ||
}); | ||
ftp.put(filePath, new Buffer("test"), handler); | ||
ftp.get(filePath, function(err, data) { | ||
assert.ok(!err, err); | ||
assert.ok(data); | ||
assert.ok(counter == 2); | ||
next() | ||
}); | ||
}); | ||
function handler() { counter++; }; | ||
function handler() { counter++; }; | ||
}, | ||
@@ -340,32 +310,30 @@ | ||
ftp.auth(FTPCredentials.user, FTPCredentials.pass, function(err, res) { | ||
ftp.raw.pwd(function(err, res) { | ||
var parent, pathDir, path; | ||
if (remoteCWD.charAt(0) !== "/") { | ||
parent = /.*"(.*)".*/.exec(res.text)[1]; | ||
pathDir = Path.resolve(parent + "/" + remoteCWD); | ||
path = Path.resolve(pathDir + "/" + file1); | ||
} | ||
else { | ||
pathDir = remoteCWD; | ||
path = Path.resolve(remoteCWD + "/" + file1); | ||
} | ||
ftp.raw.pwd(function(err, res) { | ||
var parent, pathDir, path; | ||
if (remoteCWD.charAt(0) !== "/") { | ||
parent = /.*"(.*)".*/.exec(res.text)[1]; | ||
pathDir = Path.resolve(parent + "/" + remoteCWD); | ||
path = Path.resolve(pathDir + "/" + file1); | ||
} | ||
else { | ||
pathDir = remoteCWD; | ||
path = Path.resolve(remoteCWD + "/" + file1); | ||
} | ||
ftp.put(path, new Buffer("test"), function(err, res) { | ||
assert.ok(!err); | ||
ftp.put(path, new Buffer("test"), function(err, res) { | ||
assert.ok(!err); | ||
ftp.raw.cwd(pathDir, function(err, res) { | ||
ftp.ls(".", function(err, res) { | ||
assert.ok(!err); | ||
ftp.raw.cwd(pathDir, function(err, res) { | ||
ftp.ls(".", function(err, res) { | ||
assert.ok(!err); | ||
assert.ok(Array.isArray(res)); | ||
assert.ok(Array.isArray(res)); | ||
var fileNames = res.map(function(file) { | ||
return file ? file.name : null; | ||
}); | ||
var fileNames = res.map(function(file) { | ||
return file ? file.name : null; | ||
}); | ||
assert.ok(fileNames.indexOf(file1) > -1); | ||
assert.ok(fileNames.indexOf(file1) > -1); | ||
next(); | ||
}); | ||
next(); | ||
}); | ||
@@ -382,32 +350,28 @@ }); | ||
ftp.auth(FTPCredentials.user, FTPCredentials.pass, function(err, res) { | ||
ftp.raw.pwd(function(err, res) { | ||
var parent, pathDir, path1, path2, path3; | ||
if (remoteCWD.charAt(0) !== "/") { | ||
parent = /.*"(.*)".*/.exec(res.text)[1]; | ||
pathDir = Path.resolve(parent + "/" + remoteCWD); | ||
path1 = Path.resolve(pathDir + "/" + file1); | ||
path2 = Path.resolve(pathDir + "/" + file2); | ||
path3 = Path.resolve(pathDir + "/" + file3); | ||
} | ||
else { | ||
pathDir = remoteCWD; | ||
path1 = Path.resolve(remoteCWD + "/" + file1); | ||
path2 = Path.resolve(remoteCWD + "/" + file2); | ||
path3 = Path.resolve(remoteCWD + "/" + file3); | ||
} | ||
ftp.raw.pwd(function(err, res) { | ||
var parent, pathDir, path1, path2, path3; | ||
if (remoteCWD.charAt(0) !== "/") { | ||
parent = /.*"(.*)".*/.exec(res.text)[1]; | ||
pathDir = Path.resolve(parent + "/" + remoteCWD); | ||
path1 = Path.resolve(pathDir + "/" + file1); | ||
path2 = Path.resolve(pathDir + "/" + file2); | ||
path3 = Path.resolve(pathDir + "/" + file3); | ||
} | ||
else { | ||
pathDir = remoteCWD; | ||
path1 = Path.resolve(remoteCWD + "/" + file1); | ||
path2 = Path.resolve(remoteCWD + "/" + file2); | ||
path3 = Path.resolve(remoteCWD + "/" + file3); | ||
} | ||
ftp.put(path1, new Buffer("test"), handler); | ||
ftp.put(path1, new Buffer("test"), handler); | ||
ftp.put(path2, new Buffer("test"), handler); | ||
ftp.put(path3, new Buffer("test"), handler); | ||
ftp.put(path2, new Buffer("test"), handler); | ||
ftp.put(path3, new Buffer("test"), handler); | ||
var count = 0; | ||
function handler(err, res) { | ||
assert.ok(err == null); | ||
if (++count == 3) | ||
next(); | ||
} | ||
}); | ||
var count = 0; | ||
function handler(err, res) { | ||
assert.ok(!err); | ||
if (++count == 3) | ||
next(); | ||
} | ||
}); | ||
@@ -414,0 +378,0 @@ }, |
383
jsftp.js
@@ -5,3 +5,3 @@ /* | ||
* @author Sergi Mansilla <sergi.mansilla@gmail.com> | ||
* @license https://github.com/sergi/jsFTP/blob/master/LICENSE MIT License | ||
* @license https://github.com/sergi/jsftp/blob/master/LICENSE MIT License | ||
*/ | ||
@@ -11,5 +11,5 @@ | ||
var Util = require("util"); | ||
var EventEmitter = require('events').EventEmitter; | ||
var Parser = require('./lib/ftpParser'); | ||
var S = require("streamer"); | ||
var EventEmitter = require("events").EventEmitter; | ||
var Parser = require("./lib/ftpParser"); | ||
var Gab = require("gab"); | ||
@@ -22,3 +22,2 @@ var slice = Array.prototype.slice; | ||
var RE_MULTI = /^(\d{3})-/; | ||
var RE_NL_END = /\r\n$/; | ||
var RE_NL = /\r\n/; | ||
@@ -40,3 +39,3 @@ | ||
// From https://github.com/coolaj86/node-bufferjs | ||
function concat(bufs) { | ||
var concat = function(bufs) { | ||
var buffer; | ||
@@ -69,30 +68,2 @@ var length = 0; | ||
// Queue function that maintains an ordered queue of streams. | ||
var queue = function queue() { | ||
var next; | ||
var buffer = slice.call(arguments); | ||
var stream = function stream($, stop) { | ||
next = $; | ||
stream._update(); | ||
}; | ||
stream._update = function _update() { | ||
buffer.push.apply(buffer, arguments); | ||
if (next && buffer.length) { | ||
if (false !== next(buffer.shift())) | ||
_update(); | ||
else | ||
next = null; | ||
} | ||
}; | ||
return stream; | ||
}; | ||
// Enqueues an `element` in the `stream` object, which has to be a reference to | ||
// a queue. | ||
var enqueue = function enqueue(stream, element) { | ||
stream._update.apply(null, slice.call(arguments, 1)); | ||
}; | ||
// Codes from 100 to 200 are FTP marks | ||
@@ -104,5 +75,12 @@ var isMark = function isMark(code) { | ||
var Ftp = module.exports = function(cfg) { | ||
"use strict"; | ||
Gab.apply(this, arguments); | ||
var Emitter = function() { EventEmitter.call(this); }; | ||
Util.inherits(Emitter, EventEmitter); | ||
this.emitter = new Emitter(); | ||
this.raw = {}; | ||
this.data = ""; | ||
this.buffer = []; | ||
this.options = cfg; | ||
this.cmdQueue = [["NOOP", function() {}]]; | ||
// This variable will be true if the server doesn't support the `stat` | ||
@@ -113,8 +91,6 @@ // command. Since listing a directory or retrieving file properties is | ||
this.useList = false; | ||
this.currentCode = 0; | ||
if (cfg) { | ||
this.onError = cfg.onError; | ||
this.onTimeout = cfg.onTimeout; | ||
this.onConnect = cfg.onConnect; | ||
} | ||
this.host = cfg.host; | ||
this.port = cfg.port || FTP_PORT; | ||
@@ -124,16 +100,29 @@ // Generate generic methods from parameter names. They can easily be | ||
// it is the responsability of the user to validate the parameters. | ||
var self = this; | ||
COMMANDS.forEach(function(cmd) { | ||
var lcCmd = cmd.toLowerCase(); | ||
self.raw[lcCmd] = function() { | ||
COMMANDS.forEach(this.generateCommand, this); | ||
if (DEBUG_MODE) { | ||
this.emitter.on("command", this._log); | ||
this.emitter.on("response", this._log); | ||
} | ||
this.connect(this.port, this.host); | ||
}; | ||
Ftp.prototype = new Gab; | ||
Ftp.prototype.constructor = Ftp; | ||
(function() { | ||
"use strict"; | ||
this.generateCommand = function(cmd) { | ||
var self = this; | ||
cmd = cmd.toLowerCase(); | ||
this.raw[cmd] = function() { | ||
var callback; | ||
var action = lcCmd + " "; | ||
var args = slice.call(arguments); | ||
if (typeof args[args.length - 1] === "function") | ||
if (typeof args[args.length - 1] === "function") { | ||
callback = args.pop(); | ||
} | ||
action += args.join(" "); | ||
if (lcCmd === "quit" && self._keepAliveInterval) | ||
if (cmd === "quit" && self._keepAliveInterval) | ||
clearInterval(self._keepAliveInterval); | ||
@@ -151,222 +140,94 @@ else | ||
// slight slopiness in the code flow. | ||
var action = cmd + " " + args.join(" "); | ||
var isAuthCmd = /feat|user|pass/.test(action); | ||
if (!self.authenticated && !isAuthCmd) { | ||
self.auth(self.options.user, self.options.pass, function() { | ||
enqueue(self.cmdQueue, [action.trim(), callback]); | ||
self.push([action.trim(), callback]); | ||
}); | ||
} | ||
else { | ||
enqueue(self.cmdQueue, [action.trim(), callback]); | ||
self.push([action.trim(), callback]); | ||
} | ||
}; | ||
}); | ||
}, | ||
if (DEBUG_MODE) { | ||
this.on("command", this._log); | ||
this.on("response", this._log); | ||
} | ||
this.collectIncomingData = function(data) { | ||
// if (isMark(data.code)) | ||
// return; | ||
this.host = cfg.host; | ||
this.port = cfg.port || FTP_PORT; | ||
this.data += data; | ||
}, | ||
var socket = this._createSocket(this.port, this.host); | ||
// Writes a new command to the server, but before that it pushes the | ||
// command into `cmds` list. This command will get paired with its response | ||
// once that one is received | ||
this.push = function(command, callback, onWriteCallback) { | ||
if (!command || typeof command !== "string") | ||
return; | ||
this.push = function(data, onWriteCallback) { | ||
var command = data[0]; | ||
Gab.prototype.push.call(this, command + "\r\n"); | ||
var self = this; | ||
function send() { | ||
socket.write(command + "\r\n"); | ||
self.emit("command", { | ||
code: "", | ||
text: self._sanitize(command) | ||
}); | ||
this.emitter.emit("command", this._sanitize(command)); | ||
this.cmdQueue.push(data); | ||
if (onWriteCallback) | ||
onWriteCallback(); | ||
if (onWriteCallback) { | ||
onWriteCallback(); | ||
} | ||
}; | ||
if (socket.writable) { | ||
send(); | ||
} | ||
else { | ||
if (DEBUG_MODE) | ||
console.log("FTP socket is not writable, reopening socket..."); | ||
this.foundTerminator = function() { | ||
var NL = "\n"; | ||
var line = this.data.replace("\r", ""); | ||
this.data = ""; | ||
if (!this.connecting) { | ||
this.connecting = true; | ||
try { | ||
socket = this._createSocket(this.port, this.host, function() { | ||
self.connecting = false; | ||
send(); | ||
}); | ||
this.createStreams(); | ||
var simpleRes = RE_RES.exec(line); | ||
var multiRes = RE_MULTI.exec(line); | ||
if (simpleRes) { | ||
var code = parseInt(simpleRes[1], 10); | ||
if (this.buffer.length) { | ||
this.buffer.push(line); | ||
// Multiline responses from FTP signal last line by | ||
// starting the last line with the code that they started with. | ||
if (this.currentCode === code) { | ||
line = this.buffer.join(NL); | ||
this.buffer = []; | ||
this.currentCode = 0; | ||
} | ||
catch (e) { | ||
console.log(e); | ||
else { | ||
return; | ||
} | ||
} | ||
} | ||
}; | ||
// Stream of incoming data from the FTP server. | ||
var input = function(next, stop) { | ||
socket.on("connect", self.onConnect || function(){}); | ||
socket.on("data", next); | ||
socket.on("end", stop); | ||
socket.on("error", stop); | ||
socket.on("close", stop); | ||
}; | ||
var ftpResponse = { | ||
code: code, | ||
text: line | ||
}; | ||
var cmd, cmds, tasks; | ||
this.createStreams = function() { | ||
self.cmdQueue = queue(); | ||
(self.nextCmd = function nextCmd() { | ||
S.head(self.cmdQueue)(function(obj) { | ||
cmd(obj, self.nextCmd); | ||
self.push(obj[0], obj[1], obj[2] || null); | ||
}); | ||
})(); | ||
if (this.cmdQueue.length) { | ||
var cmd = this.cmdQueue.shift(); | ||
var cbk = cmd[1]; | ||
// Stream of FTP commands from the client. | ||
cmds = function(next, stop) { cmd = next; }; | ||
if (!cbk) | ||
return; | ||
/** | ||
* Zips (as in array zipping) commands with responses. This creates | ||
* a stream that keeps yielding command/response pairs as soon as each pair | ||
* becomes available. | ||
*/ | ||
tasks = S.zip(S.filter(function(x) { | ||
// We ignore FTP marks for now. They don't convey useful | ||
// information. A more elegant solution should be found in the | ||
// future. | ||
return !isMark(x.code); | ||
}, self.serverResponse(input)), S.append(S.list(null), cmds)); | ||
tasks(self.parse.bind(self), function(err) { | ||
if (DEBUG_MODE) { | ||
console.log("Ftp socket closed its doors to the public."); | ||
this.emitter.emit("response", ftpResponse.text); | ||
// In FTP every response code above 399 means error in some way. | ||
// Since the RFC is not respected by many servers, we are going to | ||
// overgeneralize and consider every value above 399 as an error. | ||
if (ftpResponse && ftpResponse.code > 399) { | ||
var err = new Error(ftpResponse.text || "Unknown FTP error."); | ||
err.code = ftpResponse.code; | ||
cbk(err); | ||
} | ||
else { | ||
cbk(null, ftpResponse); | ||
} | ||
} | ||
}); | ||
}; | ||
} | ||
else { | ||
if (!this.buffer.length && multiRes) | ||
this.currentCode = parseInt(multiRes[1], 10); | ||
this.createStreams(); | ||
this.cmd = cmd; | ||
}; | ||
Util.inherits(Ftp, EventEmitter); | ||
(function() { | ||
"use strict"; | ||
this._createSocket = function(port, host, firstTask) { | ||
this.connecting = true; | ||
var socket = this.socket = Net.createConnection(port, host); | ||
socket.setEncoding("utf8"); | ||
socket.setTimeout(TIMEOUT, function() { | ||
if (this.onTimeout) | ||
this.onTimeout(new Error("FTP socket timeout")); | ||
this.destroy(); | ||
}.bind(this)); | ||
var self = this; | ||
socket.on("connect", function() { | ||
this.emit("connected"); | ||
firstTask && firstTask(); | ||
self.connecting = false; | ||
}); | ||
return this.socket; | ||
}; | ||
/** | ||
* `serverResponse` receives a stream of responses from the server and filters | ||
* them before pushing them back into the stream. The filtering is | ||
* necessary to detect multiline responses, in which several responses from | ||
* the server belong to a single command. | ||
*/ | ||
this.serverResponse = function(source) { | ||
var NL = "\n"; | ||
var buffer = []; | ||
var currentCode = 0; | ||
return function stream(next, stop) { | ||
source(function(data) { | ||
var lines = data.replace(RE_NL_END, "").replace(RE_NL, NL).split(NL); | ||
lines.forEach(function(line) { | ||
var simpleRes = RE_RES.exec(line); | ||
var multiRes = RE_MULTI.exec(line); | ||
if (simpleRes) { | ||
var code = parseInt(simpleRes[1], 10); | ||
if (buffer.length) { | ||
buffer.push(line); | ||
// Multiline responses from FTP signal last line by | ||
// starting the last line with the code that they started with. | ||
if (currentCode === code) { | ||
line = buffer.join(NL); | ||
buffer = []; | ||
currentCode = 0; | ||
} | ||
} | ||
var data = { | ||
code: code, | ||
text: line | ||
}; | ||
this.emit("response", data); | ||
next(data); | ||
} | ||
else { | ||
if (!buffer.length && multiRes) | ||
currentCode = parseInt(multiRes[1], 10); | ||
buffer.push(line); | ||
} | ||
}, this); | ||
}, stop); | ||
}; | ||
}; | ||
/** | ||
* Parse is called each time that a comand and a request are paired | ||
* together. That is, each time that there is a round trip of actions | ||
* between the client and the server. The `exp` param contains an array | ||
* with the response from the server as a first element (text) and an array | ||
* with the command executed and the callback (if any) as the second | ||
* element. | ||
* | ||
* @param action {Array} Contains server response and client command info. | ||
*/ | ||
this.parse = function(action) { | ||
if (!action || !action[1]) | ||
return; | ||
var ftpResponse = action[0]; | ||
var command = action[1]; | ||
var callback = command[1]; | ||
var err; | ||
if (callback) { | ||
// In FTP every response code above 399 means error in some way. | ||
// Since the RFC is not respected by many servers, we are going to | ||
// overgeneralize and consider every value above 399 as an error. | ||
if (ftpResponse && ftpResponse.code > 399) { | ||
err = new Error(ftpResponse.text || "Unknown FTP error.") | ||
err.code = ftpResponse.code; | ||
callback(err); | ||
} | ||
else { | ||
callback(null, ftpResponse); | ||
} | ||
this.buffer.push(line); | ||
} | ||
this.nextCmd(); | ||
}; | ||
}, | ||
@@ -386,3 +247,3 @@ this._initialize = function(callback) { | ||
this._log = function(msg) { | ||
console.log("\n" + msg.text); | ||
console.log("\n" + msg); | ||
}; | ||
@@ -433,7 +294,4 @@ | ||
if (this.dataConn) | ||
this.dataConn.socket.destroy(); | ||
this.features = null; | ||
this.tasks = null; | ||
this.tasks = null; | ||
this.authenticated = false; | ||
@@ -528,2 +386,10 @@ }; | ||
var contents; | ||
var onConnect = function() { | ||
self.push([data.cmd], function() { | ||
if (data.onCmdWrite) | ||
data.onCmdWrite(psvSocket); | ||
}); | ||
}; | ||
var onData = function(result) { | ||
@@ -535,15 +401,13 @@ if (data.mode === "I") | ||
}; | ||
var onEnd = function(error) { | ||
callback(error, contents); | ||
}; | ||
var psvSocket = Net.createConnection(port, self.host); | ||
psvSocket.setEncoding("utf8"); | ||
psvSocket.on("connect", onConnect); | ||
psvSocket.on("data", onData); | ||
psvSocket.on("end", onEnd); | ||
psvSocket.on("error", onEnd); | ||
self.dataConn = { | ||
socket: psvSocket | ||
}; | ||
}; | ||
@@ -554,4 +418,3 @@ | ||
this.raw.type(data.mode || "I", function(err, res) { | ||
enqueue(self.cmdQueue, ["pasv", doPasv]); | ||
enqueue(self.cmdQueue, [data.cmd, null, data.onCmdWrite]); | ||
self.push(["pasv", doPasv]); | ||
}); | ||
@@ -594,8 +457,14 @@ }; | ||
cmd: "stor " + filePath, | ||
onCmdWrite: function() { | ||
var socket = self.dataConn.socket; | ||
if (socket.writable) | ||
onCmdWrite: function(socket) { | ||
if (socket && socket.writable) | ||
socket.end(buffer); | ||
}, | ||
pasvCallback: callback | ||
pasvCallback: function(error, contents) { | ||
// noop function in place because 'STOR' returns an extra command | ||
// giving the state of the transfer. | ||
if (!error) | ||
self.cmdQueue.push(["NOOP", function() {}]) | ||
callback(error, contents); | ||
} | ||
}); | ||
@@ -602,0 +471,0 @@ }; |
{ | ||
"name": "jsftp", | ||
"id": "jsftp", | ||
"version": "0.2.6", | ||
"version": "0.2.7", | ||
"description": "A sane FTP client implementation for NodeJS", | ||
"keywords": [ "ftp", "streams", "files", "server", "client", "async" ], | ||
"author": "Sergi Mansilla <sergi.mansilla@gmail.com> (http://www.sergimansilla.com)", | ||
"keywords": [ "ftp", "protocol", "files", "server", "client", "async" ], | ||
"author": "Sergi Mansilla <sergi.mansilla@gmail.com> (http://sergimansilla.com)", | ||
"homepage": "https://github.com/sergi/jsftp", | ||
@@ -17,3 +17,3 @@ "repository": { | ||
"dependencies": { | ||
"streamer": "0.2.x" | ||
"gab": ">=0.0.1" | ||
}, | ||
@@ -20,0 +20,0 @@ "devDependencies": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
328789
28
1918
5
+ Addedgab@>=0.0.1
+ Addedgab@0.0.2(transitive)
- Removedstreamer@0.2.x
- Removedstreamer@0.2.1(transitive)