Git Product home page Git Product logo

node-ftp's Introduction

Description

node-ftp is an FTP client module for node.js that provides an asynchronous interface for communicating with an FTP server.

Requirements

Install

npm i @icetee/ftp

Examples

  • Get a directory listing of the current (remote) working directory:
  var Client = require('ftp');

  var c = new Client();
  c.on('ready', function() {
    c.list(function(err, list) {
      if (err) throw err;
      console.dir(list);
      c.end();
    });
  });
  // connect to localhost:21 as anonymous
  c.connect();
  • Download remote file 'foo.txt' and save it to the local file system:
  var Client = require('ftp');
  var fs = require('fs');

  var c = new Client();
  c.on('ready', function() {
    c.get('foo.txt', function(err, stream) {
      if (err) throw err;
      stream.once('close', function() { c.end(); });
      stream.pipe(fs.createWriteStream('foo.local-copy.txt'));
    });
  });
  // connect to localhost:21 as anonymous
  c.connect();
  • Upload local file 'foo.txt' to the server:
  var Client = require('ftp');
  var fs = require('fs');

  var c = new Client();
  c.on('ready', function() {
    c.put('foo.txt', 'foo.remote-copy.txt', function(err) {
      if (err) throw err;
      c.end();
    });
  });
  // connect to localhost:21 as anonymous
  c.connect();

API

Events

  • greeting(< string >msg) - Emitted after connection. msg is the text the server sent upon connection.

  • ready() - Emitted when connection and authentication were sucessful.

  • close(< boolean >hadErr) - Emitted when the connection has fully closed.

  • end() - Emitted when the connection has ended.

  • error(< Error >err) - Emitted when an error occurs. In case of protocol-level errors, err contains a 'code' property that references the related 3-digit FTP response code.

Methods

* Note: As with the 'error' event, any error objects passed to callbacks will have a 'code' property for protocol-level errors.

  • (constructor)() - Creates and returns a new FTP client instance.

  • connect(< object >config) - (void) - Connects to an FTP server. Valid config properties:

    • host - string - The hostname or IP address of the FTP server. Default: 'localhost'

    • port - integer - The port of the FTP server. Default: 21

    • secure - mixed - Set to true for both control and data connection encryption, 'control' for control connection encryption only, or 'implicit' for implicitly encrypted control connection (this mode is deprecated in modern times, but usually uses port 990) Default: false

    • secureOptions - object - Additional options to be passed to tls.connect(). Default: (none)

    • user - string - Username for authentication. Default: 'anonymous'

    • password - string - Password for authentication. Default: 'anonymous@'

    • connTimeout - integer - How long (in milliseconds) to wait for the control connection to be established. Default: 10000

    • pasvTimeout - integer - How long (in milliseconds) to wait for a PASV data connection to be established. Default: 10000

    • keepalive - integer - How often (in milliseconds) to send a 'dummy' (NOOP) command to keep the connection alive. Default: 10000

  • end() - (void) - Closes the connection to the server after any/all enqueued commands have been executed.

  • destroy() - (void) - Closes the connection to the server immediately.

Required "standard" commands (RFC 959)

  • list([< string >path, ][< boolean >useCompression, ]< function >callback) - (void) - Retrieves the directory listing of path. path defaults to the current working directory. useCompression defaults to false. callback has 2 parameters: < Error >err, < array >list. list is an array of objects with these properties:

    * type - _string_ - A single character denoting the entry type: 'd' for directory, '-' for file (or 'l' for symlink on **\*NIX only**).
    
    * name - _string_ - The name of the entry.
    
    * size - _string_ - The size of the entry in bytes.
    
    * date - _Date_ - The last modified date of the entry.
    
    * rights - _object_ - The various permissions for this entry **(*NIX only)**.
    
        * user - _string_ - An empty string or any combination of 'r', 'w', 'x'.
    
        * group - _string_ - An empty string or any combination of 'r', 'w', 'x'.
    
        * other - _string_ - An empty string or any combination of 'r', 'w', 'x'.
    
    * owner - _string_ - The user name or ID that this entry belongs to **(*NIX only)**.
    
    * group - _string_ - The group name or ID that this entry belongs to **(*NIX only)**.
    
    * target - _string_ - For symlink entries, this is the symlink's target **(*NIX only)**.
    
    * sticky - _boolean_ - True if the sticky bit is set for this entry **(*NIX only)**.
    
  • get(< string >path, [< boolean >useCompression, ]< function >callback) - (void) - Retrieves a file at path from the server. useCompression defaults to false. callback has 2 parameters: < Error >err, < ReadableStream >fileStream.

  • put(< mixed >input, < string >destPath, [< boolean >useCompression, ]< function >callback) - (void) - Sends data to the server to be stored as destPath. input can be a ReadableStream, a Buffer, or a path to a local file. useCompression defaults to false. callback has 1 parameter: < Error >err.

  • append(< mixed >input, < string >destPath, [< boolean >useCompression, ]< function >callback) - (void) - Same as put(), except if destPath already exists, it will be appended to instead of overwritten.

  • rename(< string >oldPath, < string >newPath, < function >callback) - (void) - Renames oldPath to newPath on the server. callback has 1 parameter: < Error >err.

  • logout(< function >callback) - (void) - Logout the user from the server. callback has 1 parameter: < Error >err.

  • delete(< string >path, < function >callback) - (void) - Deletes a file, path, on the server. callback has 1 parameter: < Error >err.

  • cwd(< string >path, < function >callback) - (void) - Changes the current working directory to path. callback has 2 parameters: < Error >err, < string >currentDir. Note: currentDir is only given if the server replies with the path in the response text.

  • abort(< function >callback) - (void) - Aborts the current data transfer (e.g. from get(), put(), or list()). callback has 1 parameter: < Error >err.

  • site(< string >command, < function >callback) - (void) - Sends command (e.g. 'CHMOD 755 foo', 'QUOTA') using SITE. callback has 3 parameters: < Error >err, < _string >responseText, < integer >responseCode.

  • status(< function >callback) - (void) - Retrieves human-readable information about the server's status. callback has 2 parameters: < Error >err, < string >status.

  • ascii(< function >callback) - (void) - Sets the transfer data type to ASCII. callback has 1 parameter: < Error >err.

  • binary(< function >callback) - (void) - Sets the transfer data type to binary (default at time of connection). callback has 1 parameter: < Error >err.

Optional "standard" commands (RFC 959)

  • mkdir(< string >path, [< boolean >recursive, ]< function >callback) - (void) - Creates a new directory, path, on the server. recursive is for enabling a 'mkdir -p' algorithm and defaults to false. callback has 1 parameter: < Error >err.

  • rmdir(< string >path, [< boolean >recursive, ]< function >callback) - (void) - Removes a directory, path, on the server. If recursive, this call will delete the contents of the directory if it is not empty. callback has 1 parameter: < Error >err.

  • cdup(< function >callback) - (void) - Changes the working directory to the parent of the current directory. callback has 1 parameter: < Error >err.

  • pwd(< function >callback) - (void) - Retrieves the current working directory. callback has 2 parameters: < Error >err, < string >cwd.

  • system(< function >callback) - (void) - Retrieves the server's operating system. callback has 2 parameters: < Error >err, < string >OS.

  • listSafe([< string >path, ][< boolean >useCompression, ]< function >callback) - (void) - Similar to list(), except the directory is temporarily changed to path to retrieve the directory listing. This is useful for servers that do not handle characters like spaces and quotes in directory names well for the LIST command. This function is "optional" because it relies on pwd() being available.

Extended commands (RFC 3659)

  • size(< string >path, < function >callback) - (void) - Retrieves the size of path. callback has 2 parameters: < Error >err, < integer >numBytes.

  • lastMod(< string >path, < function >callback) - (void) - Retrieves the last modified date and time for path. callback has 2 parameters: < Error >err, < Date >lastModified.

  • restart(< integer >byteOffset, < function >callback) - (void) - Sets the file byte offset for the next file transfer action (get/put) to byteOffset. callback has 1 parameter: < Error >err.

  • mlsd([< string >path, ][< boolean >useCompression, ]< function >callback) - (void) - Retrieves the directory listing of path. path defaults to the current working directory. useCompression defaults to false. callback has 2 parameters: < Error >err, < array >list. See the list command for a list of properties. Also see https://tools.ietf.org/html/rfc3659 7.2.

Draft commands (draft-somers-ftp-mfxx-04)

  • setLastMod(< string >path, < Date >date, < function >callback) - (void) - Set modification time for path. callback has 1 parameter: < Error >err.

node-ftp's People

Contributors

avranju avatar doug65536 avatar georgephillips avatar icetee avatar kellym avatar kgilpin avatar ljxia avatar martinvl avatar maximethebault avatar mscdex avatar oldrich-svec avatar targos avatar temich avatar tp avatar unixpickle avatar victorstanciu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

node-ftp's Issues

ftps put file

In some cases when I rewrite file on ftps server file get size 0 bite. When I analyse your code I found error, in "connection.js -> FTP.prototype._store -> _pasv -> sendStore -> _send -> if (code === 150 || code === 125) -> if (isBuffer)" you send data without check that secure connection was established. As a result data not transferred to server server give code 150 and I was not see code 226. I make work around with setInterval and now it working good, but I think that my code so bad and it will be good if you resolve this issues because file with size 0 is not good.

PS. sorry for my bad English.

Send commands in latin-1

I have a server that seems to accept latin-1 and not utf-8 only, and there is currently no way, to do this, could this be added?

(node:30846) [DEP0005] DeprecationWarning:

How do I need to deal with

internal/process/warning.js:18 (node:30846) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.

Follow the example to run normally, but this error makes me uncomfortable.

ABOR on multiple requests

Hi,

i see a strange behavior when doing more that one concurrent request in passive mode.
A tcpdump trace shows that the client sends ABOR, and the server replies with No transfer to ABOR.

The catched error is the following:

Error: Timed out while making data connection
    at Timeout.<anonymous> (node_modules/@icetee/ftp/lib/connection.js:968:12)
    at Timeout.<anonymous> (node_modules/async-listener/glue.js:188:31)
    at ontimeout (timers.js:498:11)
    at tryOnTimeout (timers.js:323:5)
    at Timer.listOnTimeout (timers.js:290:5) 

My code:

myproms = [];
creditnotes.forEach(function(creditnote, i) {
  let conn = new FtpClient(ftpParams);
  myproms.push(conn.connect().then(() => {
            logger.log('debug',
              '%s Uploading %s to %s in %s', uuid,
              filename, ftpParams.ftphost, destpath);
            return conn.put(xml, destpath + "/" + filename);
          }).then(() => {
            conn.end();
            return creditnote;
          }).catch((err) => {
            conn.destroy();
            throw err;
          }));
}
return Promise.all(myproms);
class FTPClient {
[...]
  connect() {
    var that = this;
    return new Promise(function(resolve, reject) {
      that.c.on('error', function(err) {
        return reject(err);
      });
      that.c.on('ready', function() {
        that.isready = true;
        return resolve(that.c);
      });
      that.c.connect({
        host: that.host,
        user: that.username,
        password: that.password,
        connTimeout: that.ftpConnTimeout,
        pasvTimeout: that.ftpPasvTimeout,
        debug: true,
        secure: that.secure
      });
    });
  }

  put(input, path) {
    var that = this;
    return new Promise(function(resolve, reject) {
      that.c.on('error', function(err) {
        return reject(err);
      });
      that.c.put(input, path, false, function(err) {
        if (err) {
          return reject(err);
        }
        return resolve();
      });
    });
  }

[...]
}

Am i doing something wrong?

documentation - clarify put behaviour if input is a string and file does not exist

Documentation currently states the following:

put(< mixed >input, < string >destPath, [< boolean >useCompression, ]< function >callback) - (void) - Sends data to the server to be stored as destPath. input can be a ReadableStream, a Buffer, or a path to a local file. useCompression defaults to false. callback has 1 parameter: < Error >err.

If the input argument is of type string, the function checks if that string is a path to an existing file by using fs.stat. If that file does not exist, the string itself will be transferred to the remote server and saved as a file containing the string in destPath.

For me this behaviour was unclear given the above description of the put operation and I had to take a look at the actual implementation here: https://github.com/icetee/node-ftp/blob/master/lib/connection.js#L1068

reentry bug

Hi dude! did you forget to push the latest version to NPM?

FTPS - Implicit over TLS

Hey, I'm trying to connect to a FTP using implicit over TLS and this is my config :

"ftp": {
    ...,
    "port": 990,
    "secure": "implicit",
    "secureOptions": {
        "rejectUnauthorized": false
    }
}

@icetee I've seen you answer over at the original repo about the error : "Unable to make data connection( Error: connect ECONNREFUSED 127.0.0.1:40099)" and I tried your solution :

"ftp": {
    ...,
    "port": 21,
    "secure": true,
    "secureOptions": {
        "rejectUnauthorized": false
    }
}

It does not work because the FTP I'm trying to connect to does not support FTPES.
The connection is working until I start transfering data. I can get the greetings and ready events to work but as soon as I try to list or get I receive this error.

Is there any way to make this work or to diagnose where the issue is coming from so that we can try to find a solution ?

Thanks

Callback not called in .list when ECONNRESET

After creating a ftp, doing many operations on it, I get this:

Error: read ECONNRESET
    at TLSWrap.onStreamRead (internal/stream_base_commons.js:205:27) {
  errno: -4077,
  code: 'ECONNRESET',
  syscall: 'read'
}

This is from ftp.on('error', ...).

However the .list callback wasn't called at all. It's never called, and my logic just halts.

Here's where I call .list:

  return await new Promise<Array<{name: string, type: string}>>((resolve, reject) => {
      console.log("call underlying list", pathStr);
      this._ftp.list(pathStr, (err: Error, list: Ftp.ListingElement[]) => {
        if (err) {
          console.log("ftp list ended with error");
          reject(err);
        }
        console.log("ftp list ended with success");
        resolve(list);
      });
    });

Here's where I handle the more general error event, before the connection event:

return await new Promise<string>((resolve, reject) => {
      this._ftp.on("ready", () => {
        this._connected = true;
        this._connecting = false;
        console.log("ftp connected and ready");
        resolve("/");
      });
      this._ftp.on("error", err => {
        this._connected = false;
        this._connecting = false;
        console.error("ftp error", err);
        reject(err);
      });
      this._ftp.on("close", () => {
        console.log("ftp closed");
        this._connected = false
      });
      this._ftp.on("end", () => {
        console.log("ftp end");
        this._connected = false
      });
      this._ftp.connect(this._credentials);
    });

And here's the log of my application:

call underlying list /public/IMR_Donnees_Saisies/tc/flux/2020/05/12/9401/1618
ftp error Error: read ECONNRESET
    at TLSWrap.onStreamRead (internal/stream_base_commons.js:205:27) {
  errno: -4077,
  code: 'ECONNRESET',
  syscall: 'read'
}
ftp closed

So ftp does emit the error and close events, but the callback of list is never called.

DeprecationWarning: Buffer() is deprecated due to security and usability issues.

I am using promise-ftp that use this node-ftp and I am encountering an issue with the depreciated Buffer function... similar to here.

Problematic code existed here.

Full warning message:

(node:1654) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
(Use `Electron Helper (Renderer) --trace-deprecation ...` to show where the warning was created)

Expression unable to parse following directory listing

I have a following listing in FTP, the client doesn't seem to be able to parse it.

drwxr-S---    3 105207   501            18 Jul 04  2017 .pki

Update: It appears like the regex here is omitting S in the permissions and the directory listing appears to miss the size value - I wasn't able to find any RFC specification whether the size has to be specified.

Update 2: I was able to find this: https://files.stairways.com/other/ftp-list-specs-info.txt and http://cr.yp.to/ftp/list/binls.html

Update 3: I found this library which seems to handle the parsing quite good: https://github.com/patrickjuchli/basic-ftp, maybe you can take some inspiration?

REQ: Obtain a PUT write stream

Hi and thanks for updating this project.

Would it be feasible to expose a PUT write stream (or its socket) in a clean way?

Much like get() which provides a read stream, but with put() we can only set a file name. It would be very nice to have something like putStream() which we then can write arbitrarily to.

You could do interesting things with one, such as for instance piping different source files into a single ZIP archive on the FTP server.:

// see: https://github.com/archiverjs/node-archiver
var archive = archiver('zip', { zlib: { level: 9 }});

// .. connect to FTP server and obtain a FTP write stream:
var ftpWriteStream = ftpClient.putStream('filename.zip'):

archive.pipe(ftpWriteStream);  // here!

archive.append(someReadStream1, { name: 'file1.txt' });
archive.append(someReadStream2, { name: 'file2.txt' });
archive.append(someReadStream3, { name: 'file2.txt' });
archive.finalize();

//...
// Done, and one single file created directly on the FTP server
// with no need for temp on local.

Pseudo implementation:

client.putStream = function(file, callback) {
  issue STOR cmd + checks on command socket
  if OK callback with data socket
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.