Added feature discovery as per RFC 2389.

This commit is contained in:
Julien Laffaye 2013-05-19 21:54:57 +02:00
parent 2257d14f75
commit f23c3ddfab

52
ftp.go
View File

@ -25,6 +25,7 @@ const (
type ServerConn struct { type ServerConn struct {
conn *textproto.Conn conn *textproto.Conn
host string host string
features map[string]string
} }
// Entry describes a file and is returned by List(). // Entry describes a file and is returned by List().
@ -34,7 +35,7 @@ type Entry struct {
Size uint64 Size uint64
} }
// // response represent a data-connection
type response struct { type response struct {
conn net.Conn conn net.Conn
c *ServerConn c *ServerConn
@ -51,7 +52,11 @@ func Connect(addr string) (*ServerConn, error) {
} }
a := strings.SplitN(addr, ":", 2) a := strings.SplitN(addr, ":", 2)
c := &ServerConn{conn, a[0]} c := &ServerConn{
conn: conn,
host: a[0],
features: make(map[string]string),
}
_, _, err = c.conn.ReadCodeLine(StatusReady) _, _, err = c.conn.ReadCodeLine(StatusReady)
if err != nil { if err != nil {
@ -59,6 +64,12 @@ func Connect(addr string) (*ServerConn, error) {
return nil, err return nil, err
} }
err = c.feat()
if err != nil {
c.Quit()
return nil, err
}
return c, nil return c, nil
} }
@ -86,6 +97,43 @@ func (c *ServerConn) Login(user, password string) error {
return nil return nil
} }
// feat issues a FEAT FTP command to list the additional commands supported by
// the remote FTP server.
// FEAT is described in RFC 2389
func (c *ServerConn) feat() error {
code, message, err := c.cmd(-1, "FEAT")
if err != nil {
return err
}
if code != StatusSystem {
// The server does not support the FEAT command. This is not an
// error: we consider that they are no additional features.
return nil
}
lines := strings.Split(message, "\n")
for _, line := range lines {
if !strings.HasPrefix(line, " ") {
continue
}
line = strings.Trim(line, " ")
featureElements := strings.SplitN(line, " ", 2)
command := featureElements[0]
var commandDesc string
if len(featureElements) == 2 {
commandDesc = featureElements[1]
}
c.features[command] = commandDesc
}
return nil
}
// epsv issues an "EPSV" command to get a port number for a data connection. // epsv issues an "EPSV" command to get a port number for a data connection.
func (c *ServerConn) epsv() (port int, err error) { func (c *ServerConn) epsv() (port int, err error) {
_, line, err := c.cmd(StatusExtendedPassiveMode, "EPSV") _, line, err := c.cmd(StatusExtendedPassiveMode, "EPSV")