ssh2-sftp-client 5.2.1 → 5.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.org CHANGED
@@ -1,4 +1,7 @@
1
- * SSH2 SFTP Client
1
+ #+OPTONS: H:2 toc:2
2
+ #+TITLE: SSH2 SFTP Client
3
+
4
+ * Overview
2
5
 
3
6
  an SFTP client for node.js, a wrapper around [[https://github.com/mscdex/ssh2][SSH2]] which provides a high level
4
7
  convenience abstraction as well as a Promise based API.
@@ -6,20 +9,37 @@ convenience abstraction as well as a Promise based API.
6
9
  Documentation on the methods and available options in the underlying modules can
7
10
  be found on the [[https://github.com/mscdex/ssh2][SSH2]] and [[https://github.com/mscdex/ssh2-streams/blob/master/SFTPStream.md][SSH2-STREAMS]] project pages.
8
11
 
9
- Current stable release is *v5.2.1*.
12
+ Current stable release is *v5.3.2*.
10
13
 
11
14
  Code has been tested against Node versions 12.18.2 and 13.14.0
12
15
 
13
16
  Node versions < 10.x are not supported.
14
17
 
15
- _WARNING_ There is currently an issue with both the fastPut() and fastGet()
16
- methods when using Node versions greater than 14.0.0. This is a bug in the
17
- underlying ssh2-streams library and needs to be fixed upstream. The issue
18
- appears to be related to the concurrency operations of these two functions. A
19
- workaround is to set concurrency to 1 using the options object. Alternatively,
20
- use get() or put(), which do not use concurrency and which will provide the same
21
- performance as fastGet() or fastPut() when they are set to use a concurrency
22
- of 1. A bug report has been logged against the ssh2-streams library as [[https://github.com/mscdex/ssh2-streams/issues/156][issue 156]].
18
+ _WARNING_ There is currently a regression error with versions of node later than
19
+ version 14.0. It appears that when using streams with chunk sizes which exceed
20
+ the high water mark for the stream, a drain event is no longer emitted. As a
21
+ result, streams with sufficient data will hang indefinitely. This appears to
22
+ affect fastput, fastget, put and possibly get operations. Until this issue is
23
+ resolved and a new version of ssh2/ssh2-streams is released, using node v14 is
24
+ not recommended.
25
+
26
+ A bug report hass been logged against the ssh2-streams library as [[https://github.com/mscdex/ssh2-streams/issues/156][issue 156]].
27
+
28
+ _UPDATE_: The author of the upstream ssh2 and ssh2-streams module has decided on
29
+ a re-write of the ssh2 module to address the above issues as well as some other
30
+ design limitations and to allow the module to better fit in with newer versions
31
+ of node. As part of that process, the functionality of ssh2-streams is being
32
+ incorporated into the main ssh2 module and the ssh2-streams module is being
33
+ deprecated. This will require a significant update to this module and may result
34
+ in some API changes, depending on what changes in the re-write of ssh2.
35
+
36
+ To support these changes, a new branch called /version-6/ has been created. This
37
+ branch will use the newest version of ssh2 and for now is very much experimental
38
+ and subject to change.
39
+
40
+ _UPDATE_: Apparently the change in core node which cause the issue with ssh2 has
41
+ been rolled back in node version 15.3.0. Testing seems to indicate the above
42
+ issue does not exist in that version of node.
23
43
 
24
44
  * Installation
25
45
 
@@ -221,7 +241,7 @@ reset to false in preparation for the next error.
221
241
  - Fix bug in checkRemotePath() relating to poor path specifications where
222
242
  you cannot determine parent directory.
223
243
 
224
- ** Version 5.1.1
244
+ ** Version 5.1.1
225
245
  - Bug fix for unexpected close of connections. It would seem that a
226
246
  connections can be unexpectedly closed without an accompanying error event.
227
247
  As methods only looked for error events, the method promise wold never
@@ -236,26 +256,54 @@ reset to false in preparation for the next error.
236
256
  inside promise chains. Common symptom is what appears to be truncated file
237
257
  upload/download. What is really happening is that the end method is being
238
258
  called before the transfer has completed.
239
-
240
- ** Version 5.1.2
259
+
260
+ ** Version 5.1.2
241
261
  - Mainly a bug fix. We needed to add back a global close listener to ensure
242
- the sftp object is unset whenever a close event occurs. As close events can
262
+ the sftp object is unset whenever a close event occurs. As close events can
243
263
  occur outside main method calls, only having method based listeners was not
244
264
  sufficient.
245
265
  - Also added a utils.dumpListeners() method, useful when debugging issues with
246
266
  listener 'leakage' due to failure to remove listeners when no longer required.
247
-
267
+
248
268
  ** Version 5.1.3
249
269
  - Fix issue with permissions for writing to root directory
250
270
  - Cleanup tests to use less connections and eliminate need for test delays
251
- - Bumped some dependencies to latest versions
271
+ - Bumped some dependencies to latest versions
252
272
  ** Version 5.2.0
253
273
  - Add posixRename() method. This is an openssh extension added in openssh
254
274
  v4.8 and will only work on servers which support this extension.conflict
255
275
  - Bumped through2 dependency version to 4.0.2
256
276
 
257
277
  ** Version 5.2.1
258
- - Move some dev dependencies from dependencies to devDependencies.
278
+ - Move some dev dependencies from dependencies to devDependencies.
279
+ ** Version 5.2.2
280
+ - Bug fix. Some servers appear to issue errors with code 4 instead of code 2
281
+ for file not found errors. This version adds checks for error code 4 to the
282
+ stat() method. Thanks to teenangst for the fix.
283
+
284
+ ** Version 5.3.0
285
+ - Add code to only add connect() and end() event handlers if they are not
286
+ already active. For connect(), remove event handlers as late as possible to
287
+ help catch error events raised late on some platforms (like win32). don't
288
+ remove end() error handler as some platforms, like win32, send an
289
+ additional error event even after a successful and requested end() call.
290
+ - Fix path handling when connecting to a remoe SFTP server running on win32
291
+ platform. Assume server honours 'nix' path convention rather than using
292
+ native win32 path format.
293
+ - Add additional documentation on events/promises, platform quirks and
294
+ platform differences.
295
+
296
+ ** Version 5.3.1
297
+ - Fix bug in handling of relative local paths
298
+ - Modified ~get()~ and ~put()~ methods to support special purpose streams
299
+ which require ~autoClose~ to be ~false~. These methods will now look for
300
+ the ~autoClose: false~ property in the options object and if it is false,
301
+ will issue a ~destroy()~ on the underlying stream just before the promise
302
+ is resolved. The default is ~autoClose: true~ and this default should be
303
+ used unless there is a known specific reason to change it to false.
304
+ ** Version 5.3.2
305
+ - Minor README typo fixes
306
+ - Fix error in local file path checks (#294)
259
307
  * Documentation
260
308
 
261
309
  The connection options are the same as those offered by the underlying SSH2
@@ -266,50 +314,63 @@ All the methods will return a Promise, except for ~on()~ and
266
314
 
267
315
  ** Specifying Paths
268
316
 
269
- All remote paths must either be absolute e.g. ~/absolute/path/to/file~ or they
270
- can be relative with a prefix of either ~./~ (relative to current remote
271
- directory) or ~../~ (relative to parent of current remote directory) e.g.
272
- ~./relative/path/to/file~ or ~../relative/to/parent/file~. It is also possible
273
- to do things like ~../../../file~ to specify the parent of the parent of the
274
- parent of the current remote directory. The shell tilde (~~~) and common
275
- environment variables like ~$HOME~ are NOT supported.
317
+ The convention with both FTP and SFTP is that paths are specified using a
318
+ 'nix' style i.e. use '/' as the path separator. This means that even if your
319
+ SFTP server is running on a win32 platform, you should use '/' instead of '\'
320
+ as the path separator. For example, for a win32 path of 'C:\Users\fred' you
321
+ would actually use '/C:/Users/fred'. If your win32 server does not support
322
+ the 'nix' path convention, you can try setting the ~remotePathSep~ property
323
+ of the ~SftpClient~ object to the path separator of your remote server. This
324
+ *might* work, but has not been tested. Please let me know if you need to do
325
+ this and provide details of the SFTP server so that I can try to create an
326
+ appropriate environment and adjust things as necessary. At this point, I'm
327
+ not aware of any win32 based SFTP servers which do not support the 'nix' path
328
+ convention.
329
+
330
+ All remote paths must either be absolute e.g. ~/absolute/path/to/file~ or
331
+ they can be relative with a prefix of either ~./~ (relative to current remote
332
+ directory) or ~../~ (relative to parent of current remote directory) e.g.
333
+ ~./relative/path/to/file~ or ~../relative/to/parent/file~. It is also
334
+ possible to do things like ~../../../file~ to specify the parent of the
335
+ parent of the parent of the current remote directory. The shell tilde (~~~)
336
+ and common environment variables like ~$HOME~ are NOT supported.
337
+
338
+ It is important to recognise that the current remote directory may not always
339
+ be what you may expect. A lot will depend on the remote platform of the SFTP
340
+ server and how the SFTP server has been configured. When things don't seem to
341
+ be working as expected, it is often a good idea to verify your assumptions
342
+ regarding the remote directory and remote paths. One way to do this is to
343
+ login using a command line program like ~sftp~ or ~lftp~.
344
+
345
+ There is a small performance hit for using ~./~ and ~../~ as the module must
346
+ query the remote server to determine what the root path is and derive the
347
+ absolute path. Using absolute paths are therefore more efficient and likely
348
+ more robust.
349
+
350
+ When specifying file paths, ensure to include a full path i.e. include the
351
+ remote filename. Don't expect the module to append the local file name to the
352
+ path you provide. For example, the following will not work
276
353
 
277
- It is important to recognise that the current remote directory may not always be
278
- what you may expect. A lot will depend on the remote platform of the SFTP server
279
- and how the SFTP server has been configured. When things don't seem to be
280
- working as expected, it is often a good idea to verify your assumptions
281
- regarding the remote directory and remote paths. One way to do this is to login
282
- using a command line program like ~sftp~ or ~lftp~.
283
-
284
- There is a small performance hit for using ~./~ and ~../~ as the module must
285
- query the remote server to determine what the root path is and derive the
286
- absolute path. Using absolute paths are therefore more efficient and likely more
287
- robust.
288
-
289
- When specifying file paths, ensure to include a full path i.e. include the
290
- remote filename. Don't expect the module to append the local file name to the
291
- path you provide. For example, the following will not work
292
-
293
- #+begin_src javascript
294
- client.put('/home/fred/test.txt', '/remote/dir');
295
- #+end_src
354
+ #+begin_src javascript
355
+ client.put('/home/fred/test.txt', '/remote/dir');
356
+ #+end_src
296
357
 
297
- will not result in the file ~test.txt~ being copied to
298
- ~/remote/dir/test.txt~. You need to specify the target filename as well e.g.
358
+ will not result in the file ~test.txt~ being copied to
359
+ ~/remote/dir/test.txt~. You need to specify the target filename as well e.g.
299
360
 
300
- #+begin_src javascript
301
- client.put('/home/fred/test.txt', '/remote/dir/test.txt');
302
- #+end_src
361
+ #+begin_src javascript
362
+ client.put('/home/fred/test.txt', '/remote/dir/test.txt');
363
+ #+end_src
303
364
 
304
- Note that the remote file name does not have to be the same as the local file
305
- name. The following works fine;
365
+ Note that the remote file name does not have to be the same as the local file
366
+ name. The following works fine;
306
367
 
307
- #+begin_src javascript
308
- client.put('/home/fred/test.txt', '/remote/dir/test-copy.txt');
309
- #+end_src
368
+ #+begin_src javascript
369
+ client.put('/home/fred/test.txt', '/remote/dir/test-copy.txt');
370
+ #+end_src
310
371
 
311
- This will copy the local file ~test.txt~ to the remote file ~test-copy.txt~ in
312
- the directory ~/remote/dir~.
372
+ This will copy the local file ~test.txt~ to the remote file ~test-copy.txt~
373
+ in the directory ~/remote/dir~.
313
374
 
314
375
  ** Methods
315
376
 
@@ -381,7 +442,7 @@ for that package for an explanation of these values.
381
442
  password: 'borsch', // string Password for password-based user authentication
382
443
  agent: process.env.SSH_AGENT, // string - Path to ssh-agent's UNIX socket
383
444
  privateKey: fs.readFileSync('/path/to/key'), // Buffer or string that contains
384
- passphrase; 'a pass phrase', // string - For an encrypted private key
445
+ passphrase: 'a pass phrase', // string - For an encrypted private key
385
446
  readyTimeout: 20000, // integer How long (in ms) to wait for the SSH handshake
386
447
  strictVendor: true // boolean - Performs a strict server vendor check
387
448
  debug: myDebug // function - Set this to a function that receives a single
@@ -869,6 +930,12 @@ action will fail.
869
930
  - recursive :: boolean. If true, remove all files and directories in target
870
931
  directory. Defaults to false
871
932
 
933
+ *Note*: There has been at least one report that some SFTP servers will allow
934
+ non-empty directories to be removed even without the recursive flag being set to
935
+ true. While this is not standard behaviour, it is recommended that users verify
936
+ the behaviour of rmdir if there are plans to rely on the recursive flag to
937
+ prevent removal of non-empty directories.
938
+
872
939
  **** Example Use
873
940
 
874
941
  #+begin_src javascript
@@ -916,7 +983,7 @@ Delete a file on the remote server.
916
983
  Rename a file or directory from ~fromPath~ to ~toPath~. You must have the
917
984
  necessary permissions to modify the remote file.
918
985
 
919
- - fromPath :: string. Path to existing file to be renamed
986
+ - fromPath :: string. Path to existing file to be renamed
920
987
  - toPath :: string. Path to new file existing file is to be renamed to. Should
921
988
  not already exist.
922
989
 
@@ -940,7 +1007,7 @@ necessary permissions to modify the remote file.
940
1007
  #+end_src
941
1008
 
942
1009
  *** posixRename(fromPath, toPath) ==> string
943
-
1010
+
944
1011
  This method uses the openssh POSIX rename extension introduced in OpenSSH 4.8.
945
1012
  The advantage of this version of rename over standard SFTP rename is that it is
946
1013
  an atomic operation and will allow renaming a resource where the destination
@@ -970,7 +1037,7 @@ protocol and therefore is not supported on all sSFTP servers.
970
1037
  console.error(err.message);
971
1038
  });
972
1039
  #+end_src
973
-
1040
+
974
1041
  *** chmod(path, mode) ==> string
975
1042
 
976
1043
  Change the mode (read, write or execute permissions) of a remote file or
@@ -983,7 +1050,7 @@ directory.
983
1050
 
984
1051
  #+begin_src javascript
985
1052
  let path = '/path/to/remote/file.txt';
986
- let ndwMode = 0o644; // rw-r-r
1053
+ let newMode = 0o644; // rw-r-r
987
1054
  let client = new Client();
988
1055
 
989
1056
  client.connect(config)
@@ -1001,8 +1068,15 @@ directory.
1001
1068
  *** realPath(path) ===> string
1002
1069
 
1003
1070
  Converts a relative path to an absolute path on the remote server. This method
1004
- is mainly used internally to resolve remote path names. Returns '' if the
1005
- path is not valid.
1071
+ is mainly used internally to resolve remote path names.
1072
+
1073
+ *Warning*: Currently, there is a platform inconsistency with this method on
1074
+ win32 platforms. For servers running on non-win32 platforms, providing a path
1075
+ which does not exist on the remote server will result in an empty e.g. '',
1076
+ absolute path being returned. On servers running on win32 platforms, a
1077
+ normalised path will be returned even if the path does not exist on the remote
1078
+ server. It is therefore advised not to use this method to also verify a path
1079
+ exists. instead, use the ~exist()~ method.
1006
1080
 
1007
1081
  - path :: A file path, either relative or absolute. Can handle '.' and '..', but
1008
1082
  does not expand '~'.
@@ -1044,36 +1118,36 @@ using the ~on()~ method.
1044
1118
  require('dotenv').config({path: dotenvPath});
1045
1119
 
1046
1120
  const config = {
1047
- host: process.env.SFTP_SERVER,
1048
- username: process.env.SFTP_USER,
1049
- password: process.env.SFTP_PASSWORD,
1050
- port: process.env.SFTP_PORT || 22
1121
+ host: process.env.SFTP_SERVER,
1122
+ username: process.env.SFTP_USER,
1123
+ password: process.env.SFTP_PASSWORD,
1124
+ port: process.env.SFTP_PORT || 22
1051
1125
  };
1052
1126
 
1053
1127
  async function main() {
1054
- const client = new SftpClient('upload-test');
1055
- const src = path.join(__dirname, '..', 'test', 'testData', 'upload-src');
1056
- const dst = '/home/tim/upload-test';
1057
-
1058
- try {
1059
- await client.connect(config);
1060
- client.on('upload', info => {
1061
- console.log(`Listener: Uploaded ${info.source}`);
1062
- });
1063
- let rslt = await client.uploadDir(src, dst);
1064
- return rslt;
1065
- } finally {
1066
- client.end();
1067
- }
1128
+ const client = new SftpClient('upload-test');
1129
+ const src = path.join(__dirname, '..', 'test', 'testData', 'upload-src');
1130
+ const dst = '/home/tim/upload-test';
1131
+
1132
+ try {
1133
+ await client.connect(config);
1134
+ client.on('upload', info => {
1135
+ console.log(`Listener: Uploaded ${info.source}`);
1136
+ });
1137
+ let rslt = await client.uploadDir(src, dst);
1138
+ return rslt;
1139
+ } finally {
1140
+ client.end();
1141
+ }
1068
1142
  }
1069
1143
 
1070
1144
  main()
1071
- .then(msg => {
1072
- console.log(msg);
1073
- })
1074
- .catch(err => {
1075
- console.log(`main error: ${err.message}`);
1076
- });
1145
+ .then(msg => {
1146
+ console.log(msg);
1147
+ })
1148
+ .catch(err => {
1149
+ console.log(`main error: ${err.message}`);
1150
+ });
1077
1151
 
1078
1152
  #+end_src
1079
1153
 
@@ -1124,7 +1198,7 @@ the ~on()~ method.
1124
1198
  try {
1125
1199
  await client.connect(config);
1126
1200
  client.on('download', info => {
1127
- console.log(`Listener: Download ${info.source}`);
1201
+ console.log(`Listener: Download ${info.source}`);
1128
1202
  });
1129
1203
  let rslt = await client.downloadDir(src, dst);
1130
1204
  return rslt;
@@ -1188,6 +1262,115 @@ type, which will be true when the client connection was closed due to errors.
1188
1262
  Removes the specified listener from the event specified in eventType. Note that
1189
1263
  the ~end()~ method automatically removes all listeners from the client object.
1190
1264
 
1265
+ * Platform Quirks & Warnings
1266
+ ** Server Capabilities
1267
+
1268
+ All SFTP servers and platforms are not equal. Some facilities provided by
1269
+ ~ssh2-sfto-client~ either depend on capabilities of the remote server or the
1270
+ underlying capabilities of the remote server platform. As an example,
1271
+ consider ~chmod()~. This command depends on a remote filesystem which
1272
+ implements the 'nix' concept of users and groups. The /win32/ platform does
1273
+ not have the same concept of users and groups, so ~chmod()~ will not behave
1274
+ in the same way.
1275
+
1276
+ One way to determine whether an issue you are encountering is due to
1277
+ ~ssh2-sftp-client~ or due to the remote server or server platform is to use a
1278
+ simple CLI sftp program, such as openSSH's sftp command. If you observe the
1279
+ same behaviour using plain ~sftp~ on the command line, the issue is likely
1280
+ due to server or remote platform limitations. Note that you should not use a
1281
+ GUI sftp client, like ~Filezilla~ or ~winSCP~ as such GUI programs often
1282
+ attempt to hide these server and platform incompatibilities and will take
1283
+ additional steps to simulate missing functionality etc. You want to use a CLI
1284
+ program which does as little as possible.
1285
+
1286
+ One way to determine whether an issue you are encountering is due to
1287
+ ~ssh2-sftp-client~ or due to the remote server or server platform is to use a
1288
+ simple CLI sftp program, such as openSSH's sftp command. If you observe the
1289
+ same behaviour using plain ~sftp~ on the command line, the issue is likely
1290
+ due to server or remote platform limitations. Note that you should not use a
1291
+ GUI sftp client, like ~Filezilla~ or ~winSCP~ as such GUI programs often
1292
+ attempt to hide these server and platform incompatibilities and will take
1293
+ additional steps to simulate missing functionality etc.
1294
+
1295
+ ** Promises & Events
1296
+
1297
+ The reality of the current Node environment is that Promises and Events don't
1298
+ play nicely together. Part of the problem is that events are asynchronous in
1299
+ nature and can occur at any time. It is very difficult to ensure an event is
1300
+ captured inside a Promise and handled appropriately. More information can be
1301
+ found in the Node documentation for Events.
1302
+
1303
+ Node v12 has introduced some experimental features to make working with
1304
+ Events and Promises a little easier. At this stage, we are not using these
1305
+ features because they are experimental and because it would mean you cannot
1306
+ use this module with Node v10. Use of these features will likely be examined
1307
+ more closely once they become stable and non-experimental.
1308
+
1309
+ So, what does this mean for this module? The ~ssh2-sftp-client~ module works
1310
+ hard to ensure things work as expected. In most cases, events are handled
1311
+ appropriately. However, there are some edge cases where events may not be
1312
+ handled and you may see an uncaught error exception. The most common place to
1313
+ see this is when you keep an SFTP connection open, but don't use it for some
1314
+ time. When the connection is open, but no methods are active (running), there
1315
+ are no error handlers defined. Should an error event be emitted (for exmaple,
1316
+ because the network connection has been lost), there is no handler and you
1317
+ will get an uncaught error exception.
1318
+
1319
+ One way to handle this is to add your own error handler using the on()
1320
+ method. Note however, you need to be careful how many times your error
1321
+ handler is added. If you begin to see a warning about a possible memory leak,
1322
+ it is an indication your error handler is being added multiple times (Node
1323
+ will generate this warning if it finds more than 11 listeners attached to an
1324
+ event emitter).
1325
+
1326
+ The other issue that can occur is that in some rare cases, the error message
1327
+ you get will be potentially misleading. For example, SFTP servers running on
1328
+ Windows appear to emit an /ECONNRESET/ error in addition to the main error
1329
+ (for example, for failed authentication). This can result in an error which
1330
+ looks like a connection was reset by the remote host when in fact the real
1331
+ error was due to bad authentication (bad password or bad username). This
1332
+ situation can be made even worse by some platforms which deliberately hide
1333
+ the real error for security reasons e.g. does not report an error indicating
1334
+ a bad username because that information can be used to try and identify
1335
+ legitimate usernames. While this module attempts to provide meaningful error
1336
+ messages which can assist developers track down problems, it is a good idea
1337
+ to consider these errors with a grain of salt and verify the error when
1338
+ possible.
1339
+
1340
+ ** Windows Based Servers
1341
+
1342
+ It appears that when the sftp server is running on Windows, a /ECONNRESET/
1343
+ error signal is raised when the end() method is called. Unfortunately, this
1344
+ signal is raised after a considerable delay. This means we cannot remove the
1345
+ error handler used in the end() promise as otherwise you will get an uncaught
1346
+ exception error. Leaving the handler in place, even though we will ignore
1347
+ this error, solves that issue, but unfortunately introduces a new problem.
1348
+ Because we are not removing the listener, if you re-use the client object for
1349
+ subsequent connections, an additional error handler will be added. If this
1350
+ happens more than 11 times, you will eventually see the Node warning about a
1351
+ possible memory leak. This is because node monitors the number of error
1352
+ handlers and if it sees more than 11 added to an object, it assumes there is
1353
+ a problem and generates the warning.
1354
+
1355
+ The best way to avoid this issue is to not re-use client objects. Always
1356
+ generate a new sftp client object for each new connection.
1357
+
1358
+ ** Don't Re-use SftpClient Objects
1359
+
1360
+ Due to an issue with /ECONNRESET/ error signals when connecting to Windows
1361
+ based SFTP servers, it is not possible to remove the error handler in the
1362
+ end() method. This means that if you re-use the SftpClient object for
1363
+ multiple connections e.g. calling connect(), then end(), then connect() etc,
1364
+ you run the risk of multiple error handlers being added to the SftpClient
1365
+ object. After 11 handlers have been added, Node will generate a possible
1366
+ memory leak warning.
1367
+
1368
+ To avoid this problem, don't re-use SftpClient objects. Generate a new
1369
+ SftpClient object for each connection. You can perform multiple actions with
1370
+ a single connection e.g. upload multiple files, download multiple files etc,
1371
+ but after you have called end(), you should not try to re-use the object with
1372
+ a further connect() call. Create a new object instead.
1373
+
1191
1374
  * FAQ
1192
1375
 
1193
1376
  ** Remote server drops connections with only an end event
@@ -1217,7 +1400,7 @@ openSSH is =10:30:60=, so you really just need to have enough delay to ensure
1217
1400
  that the 1st connection has completed authentication before the 11th connection
1218
1401
  is attempted.
1219
1402
 
1220
- ** How can you pass writable stream as dst for get method?
1403
+ ** How can I pass writable stream as dst for get method?
1221
1404
 
1222
1405
  If the dst argument passed to the get method is a writeable stream, the remote
1223
1406
  file will be piped into that writeable. If the writeable you pass in is a
@@ -1361,6 +1544,47 @@ host key used to establish the initial secure connection. See the SSH2
1361
1544
  documentation for details. Getting these parameters correct usually resolves the
1362
1545
  issue.
1363
1546
 
1547
+ ** How can I limit upload/download speed
1548
+
1549
+ If you want to limit the amount of bandwidth used during upload/download of
1550
+ data, you can use a stream to limit throughput. The following example was
1551
+ provided by /kennylbj/. Note that there is a caveat that we must set the
1552
+ ~autoClose~ flag to false to avoid calling an extra ~_read()~ on a closed stream
1553
+ that may cause _get Permission Denied error in ssh2-streams.
1554
+
1555
+
1556
+ #+begin_src javascript
1557
+
1558
+
1559
+ const Throttle = require('throttle');
1560
+ const progress = require('progress-stream');
1561
+
1562
+ // limit download speed
1563
+ const throttleStream = new Throttle(config.throttle);
1564
+
1565
+ // download progress stream
1566
+ const progressStream = progress({
1567
+ length: fileSize,
1568
+ time: 500,
1569
+ });
1570
+ progressStream.on('progress', (progress) => {
1571
+ console.log(progress.percentage.toFixed(2));
1572
+ });
1573
+
1574
+ const outStream = createWriteStream(localPath);
1575
+
1576
+ // pipe streams together
1577
+ throttleStream.pipe(progressStream).pipe(outStream);
1578
+
1579
+ try {
1580
+ // set autoClose to false
1581
+ await client.get(remotePath, throttleStream, { autoClose: false });
1582
+ } catch (e) {
1583
+ console.log('sftp error', e);
1584
+ } finally {
1585
+ await client.end();
1586
+ }
1587
+ #+end_src
1364
1588
  * Examples
1365
1589
 
1366
1590
  I have started collecting example scripts in the example directory of the
@@ -1369,195 +1593,6 @@ issues or provide samples for users. They are not robust, lack adequate error
1369
1593
  handling and may contain errors. However, I think they are still useful for
1370
1594
  helping developers see how the module and API can be used.
1371
1595
 
1372
- * Change Log
1373
- ** v5.2.1 (Prod Version)
1374
- - Move some dependencies into dev-Dependencies
1375
- ** v5.2.0
1376
- - Add new method posixRename() which uses the openSSH POSIX rename extension.
1377
- ** v5.1.3
1378
- - Fix bug when writing to root directory and failure due to not being able to
1379
- determine parent
1380
- - Refactor some tests to eliminate need to have artificial delays between
1381
- tests
1382
- - Bumped some dependency versions to latest version
1383
- ** v5.1.2
1384
- - Added back global close handler
1385
- - Added dumpListeners() method
1386
-
1387
- ** v5.1.1
1388
- - Added separate close handlers to each method.
1389
- - Added missing return statement in connect method
1390
- - Added additional troubleshooting documentation for
1391
- common errors.
1392
-
1393
- ** v5.1.0
1394
- - Fix bug in checkRemotePath() relating to handling of badly
1395
- specified paths (issue #213)
1396
- - Added additional debugging support
1397
- - Add missing test for valid connection in end() method.
1398
- - Bump ssh2 version to v0.8.8
1399
-
1400
- ** v5.0.2
1401
- - Fix bugs related to win32 platform and local tests for valid directories
1402
- - Fix problem with parsing of file paths
1403
-
1404
- ** v5.0.1
1405
- - Turn down error checking to be less stringent and handle situations
1406
- where user does not have read permission on parent directory.
1407
-
1408
- ** v5.0.0
1409
- - Added two new methods ~uploadDir()~ and ~downloadDir()~
1410
- - Removed deprecated ~auxList()~ method
1411
- - Improved error message consistency
1412
- - Added additional error checking to enable more accurate and useful error
1413
- messages.
1414
- - Added default error handler to deal with event errors which fire outside of
1415
- active SftpClient methods (i.e. connection unexpectedly reset by remote host).
1416
- - Modified event handlers to ensure that only event handlers added by the
1417
- module are removed by the module (users now responsible for removing any
1418
- custom event handlers they add).
1419
- - Module error handlers added using ~prependListener~ to ensure they are
1420
- called before any additional custom handlers added by client code.
1421
- - Any error events fired during an ~end()~ call are now ignored.
1422
-
1423
- ** v4.3.1
1424
- - Updated end() method to resolve once close event fires
1425
- - Added errorListener to error event in each promise to catch error events
1426
- and reject the promise. This should resolve the issue of some error events
1427
- causing uncaughtException erros and causing the process to exit.
1428
-
1429
- ** v4.3.0
1430
- - Ensure errors include an err.code property and pass through the error code
1431
- from the originating error
1432
- - Change tests for error type to use ~error.code~ instead of matching on
1433
- ~error.message~.
1434
-
1435
- ** v4.2.4
1436
- - Bumped ssh2 to v0.8.6
1437
- - Added exists() usage example to examples directory
1438
- - Clarify documentation on get() method
1439
- ** v4.2.3
1440
- - Fix bug in ~exist()~ where tests on root directory returned false
1441
- - Minor documentation fixes
1442
- - Clean up mkdir example
1443
-
1444
- ** v4.2.2
1445
- - Minor documentation fixes
1446
- - Added additional examples in the ~example~ directory
1447
-
1448
- ** v4.2.1
1449
- - Remove default close listener. changes in ssh2 API removed the utility of a
1450
- default close listener
1451
- - Fix path handling. Under mixed environments (where client platform and
1452
- server platform were different i.e. one windows the other unix), path
1453
- handling was broken due tot he use of path.join().
1454
- - Ensure error messages include path details. Instead of errors such as "No
1455
- such file" now report "No such file /path/to/missing/file" to help with
1456
- debugging
1457
-
1458
- ** v4.2.0
1459
- - Work-around for SSH2 =end= event bug
1460
- - Added ability to set client name in constructor method
1461
- - Added additional error checking to prevent ~connect()~ being called on
1462
- already connected client
1463
- - Added additional examples in =example= directory
1464
-
1465
- ** v4.1.0
1466
- - move ~end()~ call to resolve into close hook
1467
- - Prevent ~put()~ and ~get()~ from creating empty files in destination when
1468
- unable to read source
1469
- - Expand tests for operations when lacking required permissions
1470
- - Add additional data checks for ~append()~
1471
- - Verify file exists
1472
- - Verify file is writeable
1473
- - Verify file is a regular file
1474
- - Fix handling of relative paths
1475
- - Add ~realPath()~ method
1476
- - Add ~cwd()~ method
1477
-
1478
- ** v4.0.4
1479
- - Minor documentation fix
1480
- - Fix return value from ~get()~
1481
-
1482
- ** v4.0.3
1483
- - Fix bug in mkdir() relating to handling of relative paths
1484
- - Modify exists() to always return 'd' if path is '.'
1485
-
1486
- ** v4.0.2
1487
- - Fix some minor packaging issues
1488
-
1489
- ** v4.0.0
1490
- - Remove support for node < 8.x
1491
- - Fix connection retry feature
1492
- - sftp connection object set to null when 'end' signal is raised
1493
- - Removed 'connectMethod' argument from connect method.
1494
- - Refined adding/removing of listeners in connect() and end() methods to enable
1495
- errors to be adequately caught and reported.
1496
- - Deprecate auxList() and add pattern/regexp filter option to list()
1497
- - Refactored handling of event signals to provide better feedback to clients
1498
- - Removed pointless 'permissions' property from objects returned by ~stat()~
1499
- (same as mode property). Added additional properties describing the type of
1500
- object.
1501
- - Added the ~removeListener()~ method to compliment the existing ~on()~ method.
1502
-
1503
- ** Older Versions
1504
- *** v2.5.2
1505
- - Repository transferred to theophilusx
1506
- - Fix error in package.json pointing to wrong repository
1507
-
1508
- *** v2.5.1
1509
- - Apply 4 pull requests to address minor issues prior to transfer
1510
-
1511
- *** v2.5.0
1512
- - ???
1513
-
1514
- *** v2.4.3
1515
- - merge #108, #110
1516
- - fix connect promise if connection ends
1517
-
1518
- *** v2.4.2
1519
- - merge #105
1520
- - fix windows path
1521
-
1522
- *** v2.4.1
1523
- - merge pr #99, #100
1524
- - bug fix
1525
-
1526
- *** v2.4.0
1527
- - Requires node.js v7.5.0 or above.
1528
- - merge pr #97, thanks for @theophilusx
1529
- - Remove emitter.maxListener warnings
1530
- - Upgraded ssh2 dependency from 0.5.5 to 0.6.1
1531
- - Enhanced error messages to provide more context and to be more consistent
1532
- - re-factored test
1533
- - Added new 'exists' method and re-factored mkdir/rmdir
1534
-
1535
- *** v2.3.0
1536
- - add: ~stat~ method
1537
- - add ~fastGet~ and ~fastPut~ method.
1538
- - fix: ~mkdir~ file exists decision logic
1539
-
1540
- *** v3.0.0 -- deprecate this version
1541
- - change: ~sftp.get~ will return chunk not stream anymore
1542
- - fix: get readable not emitting data events in node 10.0.0
1543
-
1544
- *** v2.1.1
1545
- - add: event listener. [[https://github.com/jyu213/ssh2-sftp-client#Event][doc]]
1546
- - add: ~get~ or ~put~ method add extra options [[https://github.com/jyu213/ssh2-sftp-client/pull/52][pr#52]]
1547
-
1548
- *** v2.0.1
1549
- - add: ~chmod~ method [[https://github.com/jyu213/ssh2-sftp-client/pull/33][pr#33]]
1550
- - update: upgrade ssh2 to V0.5.0 [[https://github.com/jyu213/ssh2-sftp-client/pull/30][pr#30]]
1551
- - fix: get method stream error reject unwork [[https://github.com/jyu213/ssh2-sftp-client/issues/22][#22]]
1552
- - fix: return Error object on promise rejection [[https://github.com/jyu213/ssh2-sftp-client/pull/20][pr#20]]
1553
-
1554
- *** v1.1.0
1555
- - fix: add encoding control support for binary stream
1556
-
1557
- *** v1.0.5:
1558
- - fix: multi image upload
1559
- - change: remove ~this.client.sftp~ to ~connect~ function
1560
-
1561
1596
  * Troubleshooting
1562
1597
 
1563
1598
  The ~ssh2-sftp-client~ module is essentially a wrapper around the ~ssh2~ and
@@ -1601,7 +1636,7 @@ trying to determine if the issue is with the underlying ~ssh2~ and
1601
1636
  There are some common errors people tend to make when using Promises or
1602
1637
  Asyc/Await. These are by far the most common problem found in issues logged
1603
1638
  against this module. Please check for some of these before logging your
1604
- issue.
1639
+ issue.
1605
1640
 
1606
1641
  *** Not returning the promise in a ~then()~ block
1607
1642
 
@@ -1611,9 +1646,9 @@ trying to determine if the issue is with the underlying ~ssh2~ and
1611
1646
  generates. Failing to do this will result in the ~then()~ block completing
1612
1647
  and your code starting execution of the next ~then()~, ~catch()~ or
1613
1648
  ~finally()~ block before your promise has been fulfilled. For exmaple, the
1614
- following will not do what you expect
1649
+ following will not do what you expect
1615
1650
 
1616
- #+begin_src javascript
1651
+ #+begin_src javascript
1617
1652
  sftp.connect(config)
1618
1653
  .then(() => {
1619
1654
  sftp.fastGet('foo.txt', 'bar.txt');
@@ -1624,14 +1659,14 @@ trying to determine if the issue is with the underlying ~ssh2~ and
1624
1659
  console.error(e.message);
1625
1660
  });
1626
1661
  #+end_src
1627
-
1662
+
1628
1663
  In the above code, the ~sftp.end()~ method will almost certainly be called
1629
- before ~sftp.gastGet()~ has been fulfilled (unless the /foo.txt/ file is
1664
+ before ~sftp.fastGet()~ has been fulfilled (unless the /foo.txt/ file is
1630
1665
  really small!). In fact, the whole promise chain will complete and exit even
1631
1666
  before the ~sftp.end()~ call has been fulfilled. The correct code would be
1632
- something like
1633
-
1634
- #+begin_src javascript
1667
+ something like
1668
+
1669
+ #+begin_src javascript
1635
1670
  sftp.connect(config)
1636
1671
  .then(() => {
1637
1672
  return sftp.fastGet('foo.txt', 'bar.txt');
@@ -1642,20 +1677,20 @@ trying to determine if the issue is with the underlying ~ssh2~ and
1642
1677
  console.error(e.message);
1643
1678
  });
1644
1679
  #+end_src
1645
-
1680
+
1646
1681
  Note the ~return~ statements. These ensure that the Promise returned by the
1647
1682
  client method is returned into the promise chain. It will be this promise
1648
1683
  the next block in the chain will wait on to be fulfilled before the next
1649
1684
  block is executed. Without the return statement, that block will return the
1650
1685
  default promise for that block, which essentially says /this block has been
1651
1686
  fulfilled/. What you really want is the promise which says /your sftp client
1652
- method call has been fulfilled/.
1687
+ method call has been fulfilled/.
1653
1688
 
1654
1689
  A common symptom of this type of error is for file uploads or download to
1655
1690
  fail to complete or for data in those files to be truncated. What is
1656
1691
  happening is that the connection is being ended before the transfer has
1657
- completed.
1658
-
1692
+ completed.
1693
+
1659
1694
  *** Mixing Promise Chains and Async/Await
1660
1695
 
1661
1696
  Another common error is to mix Promise chains and async/await calls. This is
@@ -1689,14 +1724,14 @@ trying to determine if the issue is with the underlying ~ssh2~ and
1689
1724
  returning is a fulfilled promise which says the ~then()~ block has been run
1690
1725
  (note that the await'ed promise is not being returned and is therefore
1691
1726
  outside the main Promise chain). As a result, the ~finally()~ block will be
1692
- executed before the await promise has been fulfilled.
1727
+ executed before the await promise has been fulfilled.
1693
1728
 
1694
1729
  Using async/await inside the promise chain has created unnecessary
1695
1730
  complexity and leads to incorrect assumptions regarding how the code will
1696
1731
  execute. A quick glance at the code is likely to give the impression that
1697
1732
  execution will wait for the ~sftp.fastGet()~ call to be fulfilled before
1698
1733
  continuing. This is not the case. The code would be more clearly expressed
1699
- as either
1734
+ as either
1700
1735
 
1701
1736
  #+begin_src javascript
1702
1737
  sftp.connect(config)
@@ -1711,7 +1746,7 @@ trying to determine if the issue is with the underlying ~ssh2~ and
1711
1746
  return sftp.end();
1712
1747
  });
1713
1748
  #+end_src
1714
-
1749
+
1715
1750
  *or, using async/await*
1716
1751
 
1717
1752
  #+begin_src javascript
@@ -1735,14 +1770,14 @@ trying to determine if the issue is with the underlying ~ssh2~ and
1735
1770
  signals, such as an error event. In general, you cannot use try/catch blocks
1736
1771
  for asynchronous code and expect errors to be caught by the ~catch~ block.
1737
1772
  Handling errors in asynchronous code is one of the key reasons we now have
1738
- the Promise and async/await frameworks.
1773
+ the Promise and async/await frameworks.
1739
1774
 
1740
1775
  The basic problem is that the try/catch block will have completed execution
1741
1776
  before the asynchronous code has completed. If the asynchronous code has not
1742
1777
  compleed, then there is a potential for it to raise an error. However, as
1743
1778
  the try/catch block has already completed, there is no /catch/ waiting to
1744
1779
  catch the error. It will bubble up and probably result in your script
1745
- exiting with an uncaught exception error.
1780
+ exiting with an uncaught exception error.
1746
1781
 
1747
1782
  Error events are essentially asynchronous code. You don't know when such
1748
1783
  events will fire. Therefore, you cannot use a try/catch block to catch such
@@ -1753,8 +1788,8 @@ trying to determine if the issue is with the underlying ~ssh2~ and
1753
1788
  error exceptions that cause your script to exit abnormally despite having
1754
1789
  try/catch blocks in your script. What you need to do is look at your code
1755
1790
  and find where errors are raised asynchronously and use an event handler or
1756
- some other mechanism to manage any errors raised.
1757
-
1791
+ some other mechanism to manage any errors raised.
1792
+
1758
1793
  ** Debugging Support
1759
1794
 
1760
1795
  You can add a ~debug~ property to the config object passed in to ~connect()~ to
@@ -1777,6 +1812,19 @@ using shell redirection e.g.
1777
1812
 
1778
1813
  #+end_src
1779
1814
 
1815
+ If you just want to see debug messages from ~ssh2-sftp-client~ and exclude debug
1816
+ messages from the underlying ~ssh2~ and ~ssh2-streams~ modules, you can filter
1817
+ based on messages which start with 'CLIENT' e.g.
1818
+
1819
+ #+begin_src javascript
1820
+ {
1821
+ debug: (msg) => {
1822
+ if (msg.startsWith('CLIENT')) {
1823
+ console.error(msg);
1824
+ }
1825
+ }
1826
+ }
1827
+ #+end_src
1780
1828
  * Logging Issues
1781
1829
 
1782
1830
  Please log an issue for all bugs, questions, feature and enhancement
@@ -1830,4 +1878,8 @@ Thanks to the following for their contributions -
1830
1878
  - henrytk :: Documentation fix
1831
1879
  - waldyrious :: Documentation fixes
1832
1880
  - james-pellow :: Cleanup and fix for connect method logic
1833
- - jhorbulyk :: Contributed posixRename() functionality
1881
+ - jhorbulyk :: Contributed posixRename() functionality
1882
+ - teenangst :: Contributed fix for error code 4 in stat() method
1883
+ - kennylbj :: Contributed example of using a throttle stream to limit
1884
+ upload/download bandwidth.
1885
+ - anton-erofeev :: Documentation fix