You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ftp.js 3.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /**
  2. * Module dependencies.
  3. */
  4. var FTP = require('ftp');
  5. var path = require('path');
  6. var NotFoundError = require('./notfound');
  7. var NotModifiedError = require('./notmodified');
  8. var debug = require('debug')('get-uri:ftp');
  9. /**
  10. * Module exports.
  11. */
  12. module.exports = get;
  13. /**
  14. * Returns a Readable stream from an "ftp:" URI.
  15. *
  16. * @api protected
  17. */
  18. function get (parsed, opts, fn) {
  19. var cache = opts.cache;
  20. var client = new FTP();
  21. var filepath = parsed.pathname;
  22. var lastModified;
  23. client.once('error', onerror);
  24. client.once('ready', onready);
  25. client.once('greeting', ongreeting);
  26. function onready () {
  27. // first we have to figure out the Last Modified date.
  28. // try the MDTM command first, which is an optional extension command.
  29. client.lastMod(filepath, onlastmod);
  30. }
  31. function ongreeting (greeting) {
  32. debug('FTP greeting: %o', greeting);
  33. }
  34. function onerror (err) {
  35. client.end();
  36. fn(err);
  37. }
  38. function onfile (err, stream) {
  39. if (err) return onerror(err);
  40. stream.once('end', onend);
  41. stream.lastModified = lastModified;
  42. fn(null, stream);
  43. }
  44. function onend () {
  45. // close the FTP client socket connection
  46. client.end();
  47. }
  48. function getFile () {
  49. client.get(filepath, onfile);
  50. }
  51. function onlastmod (err, lastmod) {
  52. // handle the "file not found" error code
  53. if (err) {
  54. if (550 == err.code) {
  55. onerror(new NotFoundError());
  56. }
  57. // any other error then we'll try the LIST command instead
  58. }
  59. if (lastmod) {
  60. setLastMod(lastmod);
  61. } else {
  62. // try to get the last modified date via the LIST command (uses
  63. // more bandwidth, but is more compatible with older FTP servers
  64. var dir = path.dirname(filepath);
  65. client.list(dir, onlist);
  66. }
  67. }
  68. function setLastMod (lastmod) {
  69. lastModified = lastmod;
  70. if (cache && isNotModified()) {
  71. // file is the same as in the "cache", return a not modified error
  72. onerror(new NotModifiedError());
  73. } else {
  74. // XXX: a small timeout seemed necessary otherwise FTP servers
  75. // were returning empty sockets for the file occasionally
  76. setTimeout(client.get.bind(client, filepath, onfile), 10);
  77. }
  78. }
  79. function onlist (err, list) {
  80. if (err) return onerror(err);
  81. var name = path.basename(filepath);
  82. // attempt to find the "entry" with a matching "name"
  83. var entry;
  84. for (var i = 0; i < list.length; i++) {
  85. entry = list[i];
  86. debug('file %o: %o', i, entry.name);
  87. if (entry.name == name) {
  88. break;
  89. }
  90. entry = null;
  91. }
  92. if (entry) {
  93. setLastMod(entry.date);
  94. } else {
  95. onerror(new NotFoundError());
  96. }
  97. }
  98. // called when `lastModified` is set, and a "cache" stream was provided
  99. function isNotModified () {
  100. return +cache.lastModified == +lastModified;
  101. }
  102. opts.host = parsed.hostname || parsed.host || 'localhost';
  103. opts.port = parseInt(parsed.port, 10) || 21;
  104. if (debug.enabled) opts.debug = debug;
  105. if (parsed.auth) {
  106. const [user, password] = parsed.auth.split(":");
  107. opts.user = user;
  108. opts.password = password;
  109. }
  110. client.connect(opts);
  111. }