From 850f13999bf512f0ae4ec4eb94474b4c48816d08 Mon Sep 17 00:00:00 2001 From: Dmitriy Denisov Date: Sun, 3 Jan 2016 22:17:11 +1000 Subject: [PATCH 1/3] add HasCode function add HasCode function, replace strings.HasPrefix --- ftp.go | 29 ++++++++++++++++++++--------- ftp_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/ftp.go b/ftp.go index cce5108..2915b1c 100644 --- a/ftp.go +++ b/ftp.go @@ -300,7 +300,7 @@ func (ftp *FTP) Dele(path string) (err error) { return } - if !strings.HasPrefix(line, "250") { + if !ftp.HasCode(line, 250) { return errors.New(line) } @@ -496,7 +496,7 @@ func (ftp *FTP) Stor(path string, r io.Reader) (err error) { return } - if !strings.HasPrefix(line, "150") { + if !ftp.HasCode(line, 150) { err = errors.New(line) return } @@ -511,7 +511,7 @@ func (ftp *FTP) Stor(path string, r io.Reader) (err error) { return } - if !strings.HasPrefix(line, "226") { + if !ftp.HasCode(line, 226) { err = errors.New(line) return } @@ -545,7 +545,7 @@ func (ftp *FTP) Retr(path string, retrFn RetrFunc) (s string, err error) { return } - if !strings.HasPrefix(line, "150") { + if !ftp.HasCode(line, 150) { err = errors.New(line) return } @@ -560,7 +560,7 @@ func (ftp *FTP) Retr(path string, retrFn RetrFunc) (s string, err error) { return } - if !strings.HasPrefix(line, "226") { + if !ftp.HasCode(line, 226) { err = errors.New(line) return } @@ -571,7 +571,7 @@ func (ftp *FTP) Retr(path string, retrFn RetrFunc) (s string, err error) { // login to the server func (ftp *FTP) Login(username string, password string) (err error) { if _, err = ftp.cmd("331", "USER %s", username); err != nil { - if strings.HasPrefix(err.Error(), "230") { + if ftp.HasCode(err.Error(), 230) { // Ok, probably anonymous server // but login was fine, so return no error err = nil @@ -653,7 +653,7 @@ func (ftp *FTP) List(path string) (files []string, err error) { return } - if !strings.HasPrefix(line, "150") { + if !ftp.HasCode(line, 150) { // MLSD failed, lets try LIST if err = ftp.send("LIST %s", path); err != nil { return @@ -663,7 +663,7 @@ func (ftp *FTP) List(path string) (files []string, err error) { return } - if !strings.HasPrefix(line, "150") { + if !ftp.HasCode(line, 150) { // Really list is not working here err = errors.New(line) return @@ -690,10 +690,21 @@ func (ftp *FTP) List(path string) (files []string, err error) { return } - if !strings.HasPrefix(line, "226") { + if !ftp.HasCode(line, 226) { err = errors.New(line) return } return } + +func (ftp *FTP) HasCode(line string, code int) bool { + lineCode, _, err := ftp.getCode(line) + if err != nil { + return false + } + if lineCode == code { + return true + } + return false +} diff --git a/ftp_test.go b/ftp_test.go index 386e2b0..fbe6622 100644 --- a/ftp_test.go +++ b/ftp_test.go @@ -199,3 +199,32 @@ func TestGetCode(t *testing.T) { } } } + +func TestHasCode(t *testing.T) { + var tests = []struct { + input string + code int + want bool + }{ + {"220 test", 220, true}, + {"220 test", 220, true}, + {" 220 test", 220, true}, + {"220- test", 220, true}, + {"123-Firstline", 123, true}, + {"123-First line", 123, true}, + + {"220asdf test", 220, false}, + {"", 220, false}, + {"\r\n", 220, false}, + {"220 test", 550, false}, + {"220 test", 550, false}, + } + ftp := &FTP{} + for _, test := range tests { + hasCode := ftp.HasCode(test.input, test.code) + if hasCode != test.want { + t.Errorf("input %q, code: %d, want: %#v, expected: %#v", test.input, + test.code, test.want, hasCode) + } + } +} From f2291c15c040b8264e9633c72fd91e12736f2f58 Mon Sep 17 00:00:00 2001 From: Dmitriy Denisov Date: Sun, 3 Jan 2016 22:27:37 +1000 Subject: [PATCH 2/3] FTP.cmd need expected code of type int as arg --- ftp.go | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/ftp.go b/ftp.go index 2915b1c..60c384d 100644 --- a/ftp.go +++ b/ftp.go @@ -133,7 +133,7 @@ func (ftp *FTP) Walk(path string, walkFn WalkFunc, deepLimit ...int) (err error) // send quit to the server and close the connection func (ftp *FTP) Quit() (err error) { - if _, err := ftp.cmd("221", "QUIT"); err != nil { + if _, err := ftp.cmd(221, "QUIT"); err != nil { return err } @@ -145,7 +145,7 @@ func (ftp *FTP) Quit() (err error) { // will send a NOOP (no operation) to the server func (ftp *FTP) Noop() (err error) { - _, err = ftp.cmd("200", "NOOP") + _, err = ftp.cmd(200, "NOOP") return } @@ -234,7 +234,7 @@ func (ftp *FTP) RawCmd(command string, args ...interface{}) (code int, line stri } // private function to send command and compare return code with expects -func (ftp *FTP) cmd(expects string, command string, args ...interface{}) (line string, err error) { +func (ftp *FTP) cmd(expects int, command string, args ...interface{}) (line string, err error) { if err = ftp.send(command, args...); err != nil { return } @@ -243,7 +243,7 @@ func (ftp *FTP) cmd(expects string, command string, args ...interface{}) (line s return } - if !strings.HasPrefix(line, expects) { + if !ftp.HasCode(line, expects) { err = errors.New(line) return } @@ -253,11 +253,11 @@ func (ftp *FTP) cmd(expects string, command string, args ...interface{}) (line s // rename file func (ftp *FTP) Rename(from string, to string) (err error) { - if _, err = ftp.cmd("350", "RNFR %s", from); err != nil { + if _, err = ftp.cmd(350, "RNFR %s", from); err != nil { return } - if _, err = ftp.cmd("250", "RNTO %s", to); err != nil { + if _, err = ftp.cmd(250, "RNTO %s", to); err != nil { return } @@ -266,14 +266,14 @@ func (ftp *FTP) Rename(from string, to string) (err error) { // make directory func (ftp *FTP) Mkd(path string) error { - _, err := ftp.cmd("257", "MKD %s", path) + _, err := ftp.cmd(257, "MKD %s", path) return err } // get current path func (ftp *FTP) Pwd() (path string, err error) { var line string - if line, err = ftp.cmd("257", "PWD"); err != nil { + if line, err = ftp.cmd(257, "PWD"); err != nil { return } @@ -285,7 +285,7 @@ func (ftp *FTP) Pwd() (path string, err error) { // change current path func (ftp *FTP) Cwd(path string) (err error) { - _, err = ftp.cmd("250", "CWD %s", path) + _, err = ftp.cmd(250, "CWD %s", path) return } @@ -309,7 +309,7 @@ func (ftp *FTP) Dele(path string) (err error) { // secures the ftp connection by using TLS func (ftp *FTP) AuthTLS(config tls.Config) error { - if _, err := ftp.cmd("234", "AUTH TLS"); err != nil { + if _, err := ftp.cmd(234, "AUTH TLS"); err != nil { return err } @@ -320,11 +320,11 @@ func (ftp *FTP) AuthTLS(config tls.Config) error { ftp.writer = bufio.NewWriter(ftp.conn) ftp.reader = bufio.NewReader(ftp.conn) - if _, err := ftp.cmd("200", "PBSZ 0"); err != nil { + if _, err := ftp.cmd(200, "PBSZ 0"); err != nil { return err } - if _, err := ftp.cmd("200", "PROT P"); err != nil { + if _, err := ftp.cmd(200, "PROT P"); err != nil { return err } @@ -346,7 +346,7 @@ func (ftp *FTP) readAndDiscard() (int, error) { // change transfer type func (ftp *FTP) Type(t string) error { - _, err := ftp.cmd("200", "TYPE %s", t) + _, err := ftp.cmd(200, "TYPE %s", t) return err } @@ -434,7 +434,7 @@ func (ftp *FTP) send(command string, arguments ...interface{}) error { // enables passive data connection and returns port number func (ftp *FTP) Pasv() (port int, err error) { var line string - if line, err = ftp.cmd("227", "PASV"); err != nil { + if line, err = ftp.cmd(227, "PASV"); err != nil { return } @@ -570,7 +570,7 @@ func (ftp *FTP) Retr(path string, retrFn RetrFunc) (s string, err error) { // login to the server func (ftp *FTP) Login(username string, password string) (err error) { - if _, err = ftp.cmd("331", "USER %s", username); err != nil { + if _, err = ftp.cmd(331, "USER %s", username); err != nil { if ftp.HasCode(err.Error(), 230) { // Ok, probably anonymous server // but login was fine, so return no error @@ -580,7 +580,7 @@ func (ftp *FTP) Login(username string, password string) (err error) { } } - if _, err = ftp.cmd("230", "PASS %s", password); err != nil { + if _, err = ftp.cmd(230, "PASS %s", password); err != nil { return } From 674487f97ba7829e8373208e0fa5f7f5249ab2d2 Mon Sep 17 00:00:00 2001 From: Dmitriy Denisov Date: Sun, 3 Jan 2016 22:47:09 +1000 Subject: [PATCH 3/3] replace status codes with constants --- ftp.go | 46 +++++++++++++++++++++--------------------- ftp_code.go | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 23 deletions(-) create mode 100644 ftp_code.go diff --git a/ftp.go b/ftp.go index 60c384d..b21f8f5 100644 --- a/ftp.go +++ b/ftp.go @@ -133,7 +133,7 @@ func (ftp *FTP) Walk(path string, walkFn WalkFunc, deepLimit ...int) (err error) // send quit to the server and close the connection func (ftp *FTP) Quit() (err error) { - if _, err := ftp.cmd(221, "QUIT"); err != nil { + if _, err := ftp.cmd(CodeServiceClosingControlConnection, "QUIT"); err != nil { return err } @@ -145,7 +145,7 @@ func (ftp *FTP) Quit() (err error) { // will send a NOOP (no operation) to the server func (ftp *FTP) Noop() (err error) { - _, err = ftp.cmd(200, "NOOP") + _, err = ftp.cmd(CodeCommandOk, "NOOP") return } @@ -253,11 +253,11 @@ func (ftp *FTP) cmd(expects int, command string, args ...interface{}) (line stri // rename file func (ftp *FTP) Rename(from string, to string) (err error) { - if _, err = ftp.cmd(350, "RNFR %s", from); err != nil { + if _, err = ftp.cmd(CodeRequestedFileActionPending, "RNFR %s", from); err != nil { return } - if _, err = ftp.cmd(250, "RNTO %s", to); err != nil { + if _, err = ftp.cmd(CodeRequestedFileActionOk, "RNTO %s", to); err != nil { return } @@ -266,14 +266,14 @@ func (ftp *FTP) Rename(from string, to string) (err error) { // make directory func (ftp *FTP) Mkd(path string) error { - _, err := ftp.cmd(257, "MKD %s", path) + _, err := ftp.cmd(CodePathnameCreated, "MKD %s", path) return err } // get current path func (ftp *FTP) Pwd() (path string, err error) { var line string - if line, err = ftp.cmd(257, "PWD"); err != nil { + if line, err = ftp.cmd(CodePathnameCreated, "PWD"); err != nil { return } @@ -285,7 +285,7 @@ func (ftp *FTP) Pwd() (path string, err error) { // change current path func (ftp *FTP) Cwd(path string) (err error) { - _, err = ftp.cmd(250, "CWD %s", path) + _, err = ftp.cmd(CodeRequestedFileActionOk, "CWD %s", path) return } @@ -300,7 +300,7 @@ func (ftp *FTP) Dele(path string) (err error) { return } - if !ftp.HasCode(line, 250) { + if !ftp.HasCode(line, CodeRequestedFileActionOk) { return errors.New(line) } @@ -309,7 +309,7 @@ func (ftp *FTP) Dele(path string) (err error) { // secures the ftp connection by using TLS func (ftp *FTP) AuthTLS(config tls.Config) error { - if _, err := ftp.cmd(234, "AUTH TLS"); err != nil { + if _, err := ftp.cmd(CodeAuthMechanismAccepted, "AUTH TLS"); err != nil { return err } @@ -320,11 +320,11 @@ func (ftp *FTP) AuthTLS(config tls.Config) error { ftp.writer = bufio.NewWriter(ftp.conn) ftp.reader = bufio.NewReader(ftp.conn) - if _, err := ftp.cmd(200, "PBSZ 0"); err != nil { + if _, err := ftp.cmd(CodeCommandOk, "PBSZ 0"); err != nil { return err } - if _, err := ftp.cmd(200, "PROT P"); err != nil { + if _, err := ftp.cmd(CodeCommandOk, "PROT P"); err != nil { return err } @@ -346,7 +346,7 @@ func (ftp *FTP) readAndDiscard() (int, error) { // change transfer type func (ftp *FTP) Type(t string) error { - _, err := ftp.cmd(200, "TYPE %s", t) + _, err := ftp.cmd(CodeCommandOk, "TYPE %s", t) return err } @@ -434,7 +434,7 @@ func (ftp *FTP) send(command string, arguments ...interface{}) error { // enables passive data connection and returns port number func (ftp *FTP) Pasv() (port int, err error) { var line string - if line, err = ftp.cmd(227, "PASV"); err != nil { + if line, err = ftp.cmd(CodeEnteringPassiveMode, "PASV"); err != nil { return } @@ -496,7 +496,7 @@ func (ftp *FTP) Stor(path string, r io.Reader) (err error) { return } - if !ftp.HasCode(line, 150) { + if !ftp.HasCode(line, CodeFileStatusOk) { err = errors.New(line) return } @@ -511,7 +511,7 @@ func (ftp *FTP) Stor(path string, r io.Reader) (err error) { return } - if !ftp.HasCode(line, 226) { + if !ftp.HasCode(line, CodeClosingDataConnection) { err = errors.New(line) return } @@ -545,7 +545,7 @@ func (ftp *FTP) Retr(path string, retrFn RetrFunc) (s string, err error) { return } - if !ftp.HasCode(line, 150) { + if !ftp.HasCode(line, CodeFileStatusOk) { err = errors.New(line) return } @@ -560,7 +560,7 @@ func (ftp *FTP) Retr(path string, retrFn RetrFunc) (s string, err error) { return } - if !ftp.HasCode(line, 226) { + if !ftp.HasCode(line, CodeClosingDataConnection) { err = errors.New(line) return } @@ -570,8 +570,8 @@ func (ftp *FTP) Retr(path string, retrFn RetrFunc) (s string, err error) { // login to the server func (ftp *FTP) Login(username string, password string) (err error) { - if _, err = ftp.cmd(331, "USER %s", username); err != nil { - if ftp.HasCode(err.Error(), 230) { + if _, err = ftp.cmd(CodeUserNameOkNeedPassword, "USER %s", username); err != nil { + if ftp.HasCode(err.Error(), CodeUserLoggedIn) { // Ok, probably anonymous server // but login was fine, so return no error err = nil @@ -580,7 +580,7 @@ func (ftp *FTP) Login(username string, password string) (err error) { } } - if _, err = ftp.cmd(230, "PASS %s", password); err != nil { + if _, err = ftp.cmd(CodeUserLoggedIn, "PASS %s", password); err != nil { return } @@ -653,7 +653,7 @@ func (ftp *FTP) List(path string) (files []string, err error) { return } - if !ftp.HasCode(line, 150) { + if !ftp.HasCode(line, CodeFileStatusOk) { // MLSD failed, lets try LIST if err = ftp.send("LIST %s", path); err != nil { return @@ -663,7 +663,7 @@ func (ftp *FTP) List(path string) (files []string, err error) { return } - if !ftp.HasCode(line, 150) { + if !ftp.HasCode(line, CodeFileStatusOk) { // Really list is not working here err = errors.New(line) return @@ -690,7 +690,7 @@ func (ftp *FTP) List(path string) (files []string, err error) { return } - if !ftp.HasCode(line, 226) { + if !ftp.HasCode(line, CodeClosingDataConnection) { err = errors.New(line) return } diff --git a/ftp_code.go b/ftp_code.go new file mode 100644 index 0000000..75897db --- /dev/null +++ b/ftp_code.go @@ -0,0 +1,58 @@ +package goftp + +// FTP status codes https://en.wikipedia.org/wiki/List_of_FTP_server_return_codes +const ( + CodeRestartMarker = 110 + CodeServiceReadyNNNminutes = 120 + CodeDataConnectionAlreadyOpen = 125 + CodeFileStatusOk = 150 + + CodeCommandOk = 200 + CodeCommandNotImplementedInfo = 202 + CodeSystemStatus = 211 + CodeDirectoryStatus = 212 + CodeFileStatus = 213 + CodeHelpMessage = 214 + CodeSystemType = 215 + CodeServiceReadyForNewUser = 220 + CodeServiceClosingControlConnection = 221 + CodeDataConnectionOpenNoTransferInProgress = 225 + CodeClosingDataConnection = 226 + CodeEnteringPassiveMode = 227 + CodeEnteringLongPassiveMode = 228 + CodeEnteringExtendedPassiveMode = 229 + CodeUserLoggedIn = 230 + CodeUserLoggedOut = 231 + CodeLogoutNoted = 232 + CodeAuthMechanismAccepted = 234 + CodeRequestedFileActionOk = 250 + CodePathnameCreated = 257 + + CodeUserNameOkNeedPassword = 331 + CodeNeedAccountForLogin = 332 + CodeRequestedFileActionPending = 350 + + CodeServiceNotAvaliable = 421 + CodeCantOpenDataConnection = 425 + CodeConnectionClosed = 426 + CodeInvalidUsernameOrPassword = 430 + CodeRequstedHostUnavaliable = 434 + CodeRequestedFileActionNotTaken = 450 + CodeRequestedActionAborted = 451 + CodeRequestedActionNotTaken = 452 + + CodeSyntaxError = 501 + CodeCommandNotImplementedError = 502 + CodeBadSequenceOfCommandsError = 503 + CodeCommandNotImplementedForParamError = 504 + CodeNotLoggedInError = 530 + CodeNeedAccountForStoringError = 532 + CodeFileUnavailableError = 550 + CodePageTypeunknownError = 551 + CodeExceededStorageAllocationError = 552 + CodeFileNameNotAllowedError = 553 + + CodeIntegrityProtectedReply = 631 + CodeConfidentialityAndIntegrityProtectedReply = 632 + CodeConfidentialityProtectedReply = 633 +)