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