From 9f5bef84cfb421ba37eecbc2465970af2450f9fb Mon Sep 17 00:00:00 2001 From: Dmitriy Denisov Date: Sun, 3 Jan 2016 13:37:11 +1000 Subject: [PATCH 1/3] rewrite multiline code rewrite multiline code to fix https://github.com/dutchcoders/goftp/issues/8 --- ftp.go | 36 +++++++++++++++++++++++++----------- ftp_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/ftp.go b/ftp.go index 2cf4967..d79748a 100644 --- a/ftp.go +++ b/ftp.go @@ -15,6 +15,7 @@ import ( ) var REGEX_PWD_PATH *regexp.Regexp = regexp.MustCompile(`\"(.*)\"`) +var errNoCode = errors.New("No code") type FTP struct { conn net.Conn @@ -355,35 +356,48 @@ func (ftp *FTP) receiveLine() (string, error) { if ftp.debug { log.Printf("< %s", line) } - return line, err } +func (ftp *FTP) getCode(line string) (int, bool, error) { + fields := strings.Fields(strings.Trim(line, " \r\n")) + if len(fields) == 0 { + return -1, false, errNoCode + } + + if len(fields[0]) == 3 { + if code, err := strconv.Atoi(fields[0]); err == nil { + return code, false, nil + } + } else if len(fields[0]) == 4 && fields[0][3] == '-' { + if code, err := strconv.Atoi(fields[0][:3]); err == nil { + return code, true, nil + } + } + return -1, false, errNoCode +} + func (ftp *FTP) receive() (string, error) { line, err := ftp.receiveLine() if err != nil { return line, err } - - if (len(line) >= 4) && (line[3] == '-') { + code, beginMultiline, err := ftp.getCode(line) + if err == nil && beginMultiline { //Multiline response - closingCode := line[:3] + " " + closingCode := code for { str, err := ftp.receiveLine() line = line + str if err != nil { return line, err } - if len(str) < 4 { - if ftp.debug { - log.Println("Uncorrectly terminated response") - } + code, _, err := ftp.getCode(str) + if err == nil && code == closingCode { break } else { - if str[:4] == closingCode { - break - } + //check error codes 5xx 4xx } } } diff --git a/ftp_test.go b/ftp_test.go index 9933be2..89b8b8b 100644 --- a/ftp_test.go +++ b/ftp_test.go @@ -168,3 +168,32 @@ func TestGetFilesListOnGoodServer(t *testing.T) { connection.Close() } + +type getCodeResult struct { + code int + beginMultiline bool + err error +} + +func TestGetCode(t *testing.T) { + var tests = []struct { + input string + want getCodeResult + }{ + {"220 test", getCodeResult{220, false, nil}}, + {"220 test", getCodeResult{220, false, nil}}, + {" 220 test", getCodeResult{220, false, nil}}, + {"220- test", getCodeResult{220, true, nil}}, + {"220asdf test", getCodeResult{-1, false, errNoCode}}, + {"", getCodeResult{-1, false, errNoCode}}, + {"\r\n", getCodeResult{-1, false, errNoCode}}, + } + ftp := &FTP{} + for _, test := range tests { + code, beginMultiline, err := ftp.getCode(test.input) + res := getCodeResult{code, beginMultiline, err} + if res != test.want { + t.Errorf("want: %#v, expected: %#v", test.want, res) + } + } +} From 7982d03eda7b8d22b67f1ab92919b03ef5d34d29 Mon Sep 17 00:00:00 2001 From: Dmitriy Denisov Date: Sun, 3 Jan 2016 14:15:30 +1000 Subject: [PATCH 2/3] return code=0 if code was not found in line --- ftp.go | 4 ++-- ftp_test.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ftp.go b/ftp.go index d79748a..3769852 100644 --- a/ftp.go +++ b/ftp.go @@ -362,7 +362,7 @@ func (ftp *FTP) receiveLine() (string, error) { func (ftp *FTP) getCode(line string) (int, bool, error) { fields := strings.Fields(strings.Trim(line, " \r\n")) if len(fields) == 0 { - return -1, false, errNoCode + return 0, false, errNoCode } if len(fields[0]) == 3 { @@ -374,7 +374,7 @@ func (ftp *FTP) getCode(line string) (int, bool, error) { return code, true, nil } } - return -1, false, errNoCode + return 0, false, errNoCode } func (ftp *FTP) receive() (string, error) { diff --git a/ftp_test.go b/ftp_test.go index 89b8b8b..644f7d8 100644 --- a/ftp_test.go +++ b/ftp_test.go @@ -184,9 +184,9 @@ func TestGetCode(t *testing.T) { {"220 test", getCodeResult{220, false, nil}}, {" 220 test", getCodeResult{220, false, nil}}, {"220- test", getCodeResult{220, true, nil}}, - {"220asdf test", getCodeResult{-1, false, errNoCode}}, - {"", getCodeResult{-1, false, errNoCode}}, - {"\r\n", getCodeResult{-1, false, errNoCode}}, + {"220asdf test", getCodeResult{0, false, errNoCode}}, + {"", getCodeResult{0, false, errNoCode}}, + {"\r\n", getCodeResult{0, false, errNoCode}}, } ftp := &FTP{} for _, test := range tests { From 1e1d28fb07e9f5e811adf890e76c1df1d2867ee1 Mon Sep 17 00:00:00 2001 From: Dmitriy Denisov Date: Sun, 3 Jan 2016 16:59:51 +1000 Subject: [PATCH 3/3] improved multiline code parse --- ftp.go | 9 ++++++++- ftp_test.go | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/ftp.go b/ftp.go index 3769852..cce5108 100644 --- a/ftp.go +++ b/ftp.go @@ -360,7 +360,8 @@ func (ftp *FTP) receiveLine() (string, error) { } func (ftp *FTP) getCode(line string) (int, bool, error) { - fields := strings.Fields(strings.Trim(line, " \r\n")) + trimmedLine := strings.Trim(line, " \r\n") + fields := strings.Fields(trimmedLine) if len(fields) == 0 { return 0, false, errNoCode } @@ -373,6 +374,12 @@ func (ftp *FTP) getCode(line string) (int, bool, error) { if code, err := strconv.Atoi(fields[0][:3]); err == nil { return code, true, nil } + } else { + if len(trimmedLine) >= 4 && trimmedLine[3] == '-' { + if code, err := strconv.Atoi(trimmedLine[:3]); err == nil { + return code, true, nil + } + } } return 0, false, errNoCode } diff --git a/ftp_test.go b/ftp_test.go index 644f7d8..386e2b0 100644 --- a/ftp_test.go +++ b/ftp_test.go @@ -187,6 +187,8 @@ func TestGetCode(t *testing.T) { {"220asdf test", getCodeResult{0, false, errNoCode}}, {"", getCodeResult{0, false, errNoCode}}, {"\r\n", getCodeResult{0, false, errNoCode}}, + {"123-Firstline", getCodeResult{123, true, nil}}, + {"123-First line", getCodeResult{123, true, nil}}, } ftp := &FTP{} for _, test := range tests {