Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions lib/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,4 @@ module.exports = {
RETR: true,
STOR: true,
},
LOG_LEVELS: {
ERROR: 0,
WARN: 1,
INFO: 2,
DEBUG: 3,
TRACE: 4,
},
};
151 changes: 79 additions & 72 deletions lib/FtpConnection.js

Large diffs are not rendered by default.

35 changes: 8 additions & 27 deletions lib/FtpServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@ var net = require('net');
var util = require('util');
var events = require('events');
var FtpConnection = require('./FtpConnection');
var Constants = require('./Constants');
var Logger = require('./logger');

var EventEmitter = events.EventEmitter;

// Use LOG for brevity.
var LOG = Constants.LOG_LEVELS;

function FtpServer(host, options) {
var self = this;
EventEmitter.call(self);
Expand Down Expand Up @@ -36,7 +33,11 @@ function FtpServer(host, options) {
self.getGroupFromGid = options.getGroupFromGid || function(gid, c) {
c(null, 'ftp');
};
self.debugging = options.logLevel || 0;
self.logger = Logger({
logLevel: options.logLevel || 0,
logFunction: options.logFunction,
ttyColors: options.logTtyColors,
});
self.useWriteFile = options.useWriteFile;
self.useReadFile = options.useReadFile;
self.uploadMaxSlurpSize = options.uploadMaxSlurpSize || 0;
Expand Down Expand Up @@ -67,6 +68,7 @@ FtpServer.prototype._onConnection = function(socket) {
var conn = new FtpConnection({
server: this,
socket: socket,
remoteAddress: socket.remoteAddress, // save it for logs for the lifetime of this connection
pasv: null, // passive listener server
allowedCommands: allowedCommands, // subset of allowed commands for this server
dataPort: 20,
Expand Down Expand Up @@ -97,7 +99,7 @@ FtpServer.prototype._onConnection = function(socket) {
socket.setTimeout(0);
socket.setNoDelay();

this._logIf(LOG.INFO, 'Accepted a new client connection');
this.logger.log('-', '-', 'Accepted a new client connection');
conn.respond('220 FTP server (nodeftpd) ready');

socket.on('data', function(buf) {
Expand All @@ -121,25 +123,4 @@ FtpServer.prototype._onConnection = function(socket) {
};
});

FtpServer.prototype._logIf = function(verbosity, message, conn) {
if (verbosity > this.debugging) {
return;
}
// TODO: Move this to FtpConnection.prototype._logIf.
var peerAddr = (conn && conn.socket && conn.socket.remoteAddress);
if (peerAddr) {
message = '<' + peerAddr + '> ' + message;
}
if (verbosity === LOG.ERROR) {
message = 'ERROR: ' + message;
} else if (verbosity === LOG.WARN) {
message = 'WARNING: ' + message;
}
console.log(message);
var isError = (verbosity === LOG.ERROR);
if (isError && this.debugging === LOG.TRACE) {
console.trace('Trace follows');
}
};

module.exports = FtpServer;
133 changes: 133 additions & 0 deletions lib/logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
var util = require('util');
var tty = require('tty');

// is it a tty or file?
var isatty = tty.isatty(2) && tty.isatty(1);
var stdout = process.stdout;
var stderr = process.stderr;

var colors = {
// text style
bold : ['\x1B[1m', '\x1B[22m'],
italic : ['\x1B[3m', '\x1B[23m'],
underline : ['\x1B[4m', '\x1B[24m'],
inverse : ['\x1B[7m', '\x1B[27m'],
strikethrough : ['\x1B[9m', '\x1B[29m'],
// text colors
white : ['\x1B[37m', '\x1B[39m'],
grey : ['\x1B[38;5;240m', '\x1B[39m'],
black : ['\x1B[30m', '\x1B[39m'],
blue : ['\x1B[34m', '\x1B[39m'],
cyan : ['\x1B[36m', '\x1B[39m'],
green : ['\x1B[32m', '\x1B[39m'],
magenta : ['\x1B[35m', '\x1B[39m'],
red : ['\x1B[31m', '\x1B[39m'],
yellow : ['\x1B[33m', '\x1B[39m'],
// background colors
whiteBG : ['\x1B[47m', '\x1B[49m'],
greyBG : ['\x1B[49;5;8m', '\x1B[49m'],
blackBG : ['\x1B[40m', '\x1B[49m'],
blueBG : ['\x1B[44m', '\x1B[49m'],
cyanBG : ['\x1B[46m', '\x1B[49m'],
greenBG : ['\x1B[42m', '\x1B[49m'],
magentaBG : ['\x1B[45m', '\x1B[49m'],
redBG : ['\x1B[41m', '\x1B[49m'],
yellowBG : ['\x1B[43m', '\x1B[49m'],
};

var levels = {
DEBUG : 'blue',
TRACE : 'magenta',
INFO : 'green',
WARN : 'yellow',
ERROR : 'red',
};

function colored(str, color) {
return colors[color][0] + str + colors[color][1];
}

module.exports = function(options) {
options = options || {};
options.logLevel = options.logLevel !== undefined ? options.logLevel : 255;
options.ttyColors = isatty && (options.ttyColors !== undefined ? options.ttyColors : true);

options.logLevel = process.env.NODEFTPD_LOG_LEVEL ? parseInt(process.env.NODEFTPD_LOG_LEVEL, 10) : options.logLevel;

var log = function log(level) {
level = level || 'INFO';

var ts = new Date().toISOString();
var args = Array.prototype.slice.call(arguments, 1);

if (isatty && options.ttyColors) {
level = colored(level, levels[level]);
ts = colored(ts, 'grey');
}

if (typeof args[0] === 'string') {
args[0] = ts + ' ' + level + ' ' + args[0];
} else {
args = [ts, level].concat(args);
}

if (level === 'ERROR') {
stderr.write(util.format.apply(null, args) + '\n');
} else {
stdout.write(util.format.apply(null, args) + '\n');
}
};

if (typeof options.logFunction === 'function') {
log = options.logFunction;
}

return {
log: function() {
if (options.logLevel > 1) {
log.apply(null, ['INFO'].concat(Array.prototype.slice.call(arguments)));
}
},

debug: function() {
if (options.logLevel > 2) {
log.apply(null, ['DEBUG'].concat(Array.prototype.slice.call(arguments)));
}
},

trace: function() {
if (options.logLevel > 3) {
log.apply(null, ['TRACE'].concat(Array.prototype.slice.call(arguments)));
}
},

warn: function() {
if (options.logLevel > 0) {
log.apply(null, ['WARN'].concat(Array.prototype.slice.call(arguments)));
}
},

error: function error() {
// capture error() call location
var stackErr = new Error();
Error.captureStackTrace(stackErr, error);
var loggedAt = '[' + stackErr.stack.split('\n')[1].trim() + ']';

var args = Array.prototype.slice.call(arguments);

for (var i = 0; i < args.length; i++) {
if (args[i] instanceof Error) {
var err = args[i];
args[i] = err.toString() + '\n' + util.inspect(err, false, 10, options.ttyColors);
if (err.stack) {
args[i] += '\n' + err.stack.split('\n').splice(1).join('\n');
}
}
}

args.push('\n' + loggedAt);

log.apply(null, ['ERROR'].concat(args));
},
};
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@
"jsftp": "git://github.com/sergi/jsftp.git#master",
"mocha": "^2.3.4",
"should": "~3.1.2",
"ftp": "^0.3.10"
"ftp": "^0.3.10",
"sinon": "^1.17.3"
}
}
9 changes: 5 additions & 4 deletions test/cwd-cdup.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
var common = require('./lib/common');
var sinon = require('sinon');

var logSpy = sinon.spy();

describe('CWD/CDUP commands', function() {
'use strict';
Expand All @@ -20,7 +23,7 @@ describe('CWD/CDUP commands', function() {
}

beforeEach(function(done) {
server = common.server();
server = common.server({logFunction: logSpy, logTtyColors: false});
client = common.client(done);
});

Expand All @@ -41,11 +44,9 @@ describe('CWD/CDUP commands', function() {
it('should not change to non-existent directory', function(done) {
client.raw('CWD', pathExisting, function(error, response) {
response.code.should.equal(250);
server.suppressExpecteErrMsgs.push(
/^CWD \S+: Error: ENOENT/
);
client.raw('CWD', pathExisting, function(error) {
error.code.should.equal(550);
sinon.assert.calledWithMatch(logSpy, 'ERROR', sinon.match.any, sinon.match.any, sinon.match.any, 'ENOENT');
done();
});
});
Expand Down
13 changes: 9 additions & 4 deletions test/init.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
var common = require('./lib/common');
var Client = require('jsftp');
var sinon = require('sinon');

var logSpy = sinon.spy();

describe('initialization', function() {
'use strict';
Expand Down Expand Up @@ -37,15 +40,16 @@ describe('initialization', function() {

it('should bail if getRoot fails', function(done) {
server = common.server({
logFunction: logSpy,
logTtyColors: false,
getRoot: function(connection, callback) {
server.suppressExpecteErrMsgs.push(
'getRoot signaled error [Error: intentional failure]');
callback(new Error('intentional failure'));
},
});
client = new Client(options);
client.auth(options.user, options.pass, function(error) {
error.code.should.eql(421);
sinon.assert.calledWithMatch(logSpy, 'ERROR', sinon.match.any, sinon.match.any, sinon.match.any, 'intentional failure');
done();
});
});
Expand Down Expand Up @@ -84,15 +88,16 @@ describe('initialization', function() {

it('should bail if getInitialCwd fails', function(done) {
server = common.server({
logFunction: logSpy,
logTtyColors: false,
getInitialCwd: function(connection, callback) {
server.suppressExpecteErrMsgs.push(
'getInitialCwd signaled error [Error: intentional failure]');
callback(new Error('intentional failure'));
},
});
client = new Client(options);
client.auth(options.user, options.pass, function(error) {
error.code.should.eql(421);
sinon.assert.calledWithMatch(logSpy, 'ERROR', sinon.match.any, sinon.match.any, sinon.match.any, 'intentional failure');
done();
});
});
Expand Down
44 changes: 0 additions & 44 deletions test/lib/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,8 @@ var Client = require('jsftp');
var should = require('should');

var Server = ftpd.FtpServer;
var LogLevels = ftpd.LOG_LEVELS;
var LogLevelNames = Object.keys(LogLevels).reduce(function(map, name) {
var value = LogLevels[name];
map[value] = name;
return map;
}, {});

var fixturesPath = path.join(__dirname, '../../fixture');

function toString(value) {
var isPrimitive = Object(value) !== value;
if (isPrimitive) {
return JSON.stringify(value);
} else {
return ('toString' in value) ? value.toString() : Object.prototype.toString(value);
}
}

var options = {
host: process.env.IP || '127.0.0.1',
port: process.env.port || 7002,
Expand Down Expand Up @@ -79,34 +63,6 @@ var common = module.exports = {
}
});
});
var origLogIf = server._logIf;
server.suppressExpecteErrMsgs = [];
server._logIf = function logIfNotExpected(verbosity, message, conn) {
var expecteErrMsgs = server.suppressExpecteErrMsgs;
message = String(message).split(fixturesPath).join('fixture:/');
if ((expecteErrMsgs.length > 0) && (verbosity < LogLevels.LOG_INFO)) {
var expected = expecteErrMsgs.shift();
if (message === expected) {
return;
}
if ((expected instanceof RegExp) && expected.test(message)) {
return;
}
if ((typeof expected) === 'function') {
message = expected(message);
if (message === '') {
return;
}
} else {
console.error(
'\nExpected log message:\n' + toString(expected) + '\n' +
'did not match [' + LogLevelNames[verbosity] + ']:\n' +
JSON.stringify(message)
);
}
}
return origLogIf.call(this, verbosity, message, conn);
};
server.listen(customOptions.port);
return server;
},
Expand Down
Loading