From d2efb4b29b3b0be4daf700ffd803267f07f635ea Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Sat, 18 Jul 2020 09:52:22 +0100 Subject: [PATCH] ftp: add support for --dump bodies and --dump auth See: https://forum.rclone.org/t/rclone-copy-gives-error-connection-reset-by-peer-using-ftp/17934/27 --- backend/ftp/ftp.go | 42 ++++++++++++++++++++++++++++++++++++++++++ docs/content/ftp.md | 5 +++-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/backend/ftp/ftp.go b/backend/ftp/ftp.go index 2850229a7..0c4ba87ea 100644 --- a/backend/ftp/ftp.go +++ b/backend/ftp/ftp.go @@ -8,6 +8,8 @@ import ( "net/textproto" "os" "path" + "runtime" + "strings" "sync" "time" @@ -160,6 +162,43 @@ func (f *Fs) Features() *fs.Features { return f.features } +// Enable debugging output +type debugLog struct { + mu sync.Mutex + auth bool +} + +// Write writes len(p) bytes from p to the underlying data stream. It returns +// the number of bytes written from p (0 <= n <= len(p)) and any error +// encountered that caused the write to stop early. Write must return a non-nil +// error if it returns n < len(p). Write must not modify the slice data, even +// temporarily. +// +// Implementations must not retain p. +// +// This writes debug info to the log +func (dl *debugLog) Write(p []byte) (n int, err error) { + dl.mu.Lock() + defer dl.mu.Unlock() + _, file, _, ok := runtime.Caller(1) + direction := "FTP Rx" + if ok && strings.Contains(file, "multi") { + direction = "FTP Tx" + } + lines := strings.Split(string(p), "\r\n") + if lines[len(lines)-1] == "" { + lines = lines[:len(lines)-1] + } + for _, line := range lines { + if !dl.auth && strings.HasPrefix(line, "PASS") { + fs.Debugf(direction, "PASS *****") + continue + } + fs.Debugf(direction, "%q", line) + } + return len(p), nil +} + // Open a new connection to the FTP server. func (f *Fs) ftpConnection() (*ftp.ServerConn, error) { fs.Debugf(f, "Connecting to FTP server") @@ -183,6 +222,9 @@ func (f *Fs) ftpConnection() (*ftp.ServerConn, error) { if f.opt.DisableEPSV { ftpConfig = append(ftpConfig, ftp.DialWithDisabledEPSV(true)) } + if fs.Config.Dump&(fs.DumpHeaders|fs.DumpBodies|fs.DumpRequests|fs.DumpResponses) != 0 { + ftpConfig = append(ftpConfig, ftp.DialWithDebugOutput(&debugLog{auth: fs.Config.Dump&fs.DumpAuth != 0})) + } c, err := ftp.Dial(f.dialAddr, ftpConfig...) if err != nil { fs.Errorf(f, "Error while Dialing %s: %s", f.dialAddr, err) diff --git a/docs/content/ftp.md b/docs/content/ftp.md index 68ccffd1f..3e110a628 100644 --- a/docs/content/ftp.md +++ b/docs/content/ftp.md @@ -257,8 +257,9 @@ See: the [encoding section in the overview](/overview/#encoding) for more info. ### Limitations ### -Note that since FTP isn't HTTP based the following flags don't work -with it: `--dump-headers`, `--dump-bodies`, `--dump-auth` +Note that FTP does have its own implementation of : `--dump headers`, +`--dump bodies`, `--dump auth` for debugging which isn't the same as +the HTTP based backends - it has less fine grained control. Note that `--timeout` isn't supported (but `--contimeout` is).