diff --git a/debug.go b/debug.go new file mode 100644 index 0000000..864566c --- /dev/null +++ b/debug.go @@ -0,0 +1,21 @@ +package ftp + +import "io" + +type debugWrapper struct { + conn io.ReadWriteCloser + io.Reader + io.Writer +} + +func newDebugWrapper(conn io.ReadWriteCloser, w io.Writer) io.ReadWriteCloser { + return &debugWrapper{ + Reader: io.TeeReader(conn, w), + Writer: io.MultiWriter(w, conn), + conn: conn, + } +} + +func (w *debugWrapper) Close() error { + return w.conn.Close() +} diff --git a/ftp.go b/ftp.go index 13214e3..b30e991 100644 --- a/ftp.go +++ b/ftp.go @@ -53,6 +53,7 @@ type dialOptions struct { conn net.Conn disableEPSV bool location *time.Location + debugOutput io.Writer } // Entry describes a file and is returned by List(). @@ -100,10 +101,15 @@ func DialWithOptions(addr string, options ...DialOption) (*ServerConn, error) { // If we use the domain name, we might not resolve to the same IP. remoteAddr := tconn.RemoteAddr().(*net.TCPAddr) + var sourceConn io.ReadWriteCloser = tconn + if do.debugOutput != nil { + sourceConn = newDebugWrapper(tconn, do.debugOutput) + } + c := &ServerConn{ options: do, features: make(map[string]string), - conn: textproto.NewConn(tconn), + conn: textproto.NewConn(sourceConn), host: remoteAddr.IP.String(), } @@ -178,6 +184,14 @@ func DialWithTLS(tlsConfig tls.Config) DialOption { }} } +// DialWithDebugOutput returns a DialOption that configures the ServerConn to write to the Writer +// everything it reads from the server +func DialWithDebugOutput(w io.Writer) DialOption { + return DialOption{func(do *dialOptions) { + do.debugOutput = w + }} +} + // Connect is an alias to Dial, for backward compatibility func Connect(addr string) (*ServerConn, error) { return Dial(addr)