Skip to content

Commit

Permalink
Merge pull request #4 from VincenzoLaSpesa/master
Browse files Browse the repository at this point in the history
Resolved login issues. Test routines added
  • Loading branch information
nl5887 committed May 29, 2015
2 parents 4bba46b + 6aed741 commit cfb8336
Show file tree
Hide file tree
Showing 3 changed files with 233 additions and 87 deletions.
153 changes: 75 additions & 78 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,90 +3,87 @@ goftp

Golang FTP library with Walk support.


## Features

* AUTH TLS support
* Walk

## Sample
```
package main
import (
"github.com/dutchcoders/goftp"
"crypto/tls"
)
func main() {
var err error
var ftp *goftp.FTP
// For debug messages: goftp.ConnectDbg("ftp.server.com:21")
if ftp, err = goftp.Connect("ftp.server.com:21"); err != nil {
panic(err)
}
defer ftp.Close()
config := tls.Config{
InsecureSkipVerify: true,
ClientAuth: tls.RequestClientCert,
}
if err = ftp.AuthTLS(config); err != nil {
panic(err)
}
if err = ftp.Login("username", "password"); err != nil {
panic(err)
}
if err = ftp.Cwd("/"); err != nil {
panic(err)
}
var curpath string
if curpath, err = ftp.Pwd("/"); err != nil {
panic(err)
}
fmt.Printf("Current path: %s", curpath)
var files []string
if files, err = ftp.List(""); err != nil {
panic(err)
}
fmt.Println(files)
if file, err := os.Open("/tmp/test.txt"); err!=nil {
panic(err)
}
if err := ftp.Stor("/test.txt", file); err!=nil {
panic(err)
}
err = ftp.Walk("/", func(path string, info os.FileMode, err error) error {
w := &bytes.Buffer{}
_, err = ftp.Retr(path, func(r io.Reader) error {
var hasher = sha256.New()
if _, err = io.Copy(hasher, r); err != nil {
return err
}
hash := fmt.Sprintf("%s %x", path, sha256.Sum256(nil))
fmt.Println(hash)
return err
})
return nil
})
}
```
package main
import (
"github.com/dutchcoders/goftp"
"crypto/tls"
)
func main() {
var err error
var ftp *goftp.FTP
// For debug messages: goftp.ConnectDbg("ftp.server.com:21")
if ftp, err = goftp.Connect("ftp.server.com:21"); err != nil {
panic(err)
}
defer ftp.Close()
config := tls.Config{
InsecureSkipVerify: true,
ClientAuth: tls.RequestClientCert,
}
if err = ftp.AuthTLS(config); err != nil {
panic(err)
}
if err = ftp.Login("username", "password"); err != nil {
panic(err)
}
if err = ftp.Cwd("/"); err != nil {
panic(err)
}
var curpath string
if curpath, err = ftp.Pwd("/"); err != nil {
panic(err)
}
fmt.Printf("Current path: %s", curpath)
var files []string
if files, err = ftp.List(""); err != nil {
panic(err)
}
fmt.Println(files)
if file, err := os.Open("/tmp/test.txt"); err!=nil {
panic(err)
}
if err := ftp.Stor("/test.txt", file); err!=nil {
panic(err)
}
err = ftp.Walk("/", func(path string, info os.FileMode, err error) error {
w := &bytes.Buffer{}
_, err = ftp.Retr(path, func(r io.Reader) error {
var hasher = sha256.New()
if _, err = io.Copy(hasher, r); err != nil {
return err
}
hash := fmt.Sprintf("%s %x", path, sha256.Sum256(nil))
fmt.Println(hash)
return err
})
return nil
})
}

## Contributions

Expand Down
109 changes: 100 additions & 9 deletions ftp.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,27 @@ func (ftp *FTP) Noop() (err error) {
return
}

// Send raw commands, return response as string and response code as int
func (ftp *FTP) RawCmd(command string, args ...interface{}) (code int, line string) {
if ftp.debug {
log.Printf("Raw-> %s\n", fmt.Sprintf(command, args...), code)
}

code = -1
var err error
if err = ftp.send(command, args...); err != nil {
return code, ""
}
if line, err = ftp.receive(); err != nil {
return code, ""
}
code, err = strconv.Atoi(line[:3])
if ftp.debug {
log.Printf("Raw<- <- %d \n", code)
}
return code, line
}

// 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) {
if err = ftp.send(command, args...); err != nil {
Expand Down Expand Up @@ -209,6 +230,19 @@ func (ftp *FTP) AuthTLS(config tls.Config) error {
return nil
}

// read all the buffered bytes and return
func (ftp *FTP) ReadAndDiscard() (int, error) {
var i int
var err error
buffer_size := ftp.reader.Buffered()
for i = 0; i < buffer_size; i++ {
if _, err = ftp.reader.ReadByte(); err != nil {
return i, err
}
}
return i, err
}

// change transfer type
func (ftp *FTP) Type(t string) error {
_, err := ftp.cmd("200", "TYPE %s", t)
Expand All @@ -233,12 +267,28 @@ func (ftp *FTP) receive() (string, error) {
}

if (len(line) >= 4) && (line[3] == '-') {
nextLine := ""
// This is a continuation of output line
nextLine, err = ftp.receive()
line = line + nextLine
//Multiline response
closingCode := line[:3] + " "
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")
}
break
} else {
if str[:4] == closingCode {
break
}
}
}
}

ftp.ReadAndDiscard()
//fmt.Println(line)
return line, err
}

Expand Down Expand Up @@ -398,6 +448,10 @@ func (ftp *FTP) Retr(path string, retrFn RetrFunc) (s string, err error) {
return
}

/*func GetFilesList(path string) (files []string, err error) {
}*/

// list the path (or current directory)
func (ftp *FTP) List(path string) (files []string, err error) {
if err = ftp.Type("A"); err != nil {
Expand Down Expand Up @@ -468,6 +522,40 @@ func (ftp *FTP) List(path string) (files []string, err error) {
return
}

/*
// login on server with strange login behavior
func (ftp *FTP) SmartLogin(username string, password string) (err error) {
var code int
// Maybe the server has some useless words to say. Make him talk
code, _ = ftp.RawCmd("NOOP")
if code == 220 || code == 530 {
// Maybe with another Noop the server will ask us to login?
code, _ = ftp.RawCmd("NOOP")
if code == 530 {
// ok, let's login
code, _ = ftp.RawCmd("USER %s", username)
code, _ = ftp.RawCmd("NOOP")
if code == 331 {
// user accepted, password required
code, _ = ftp.RawCmd("PASS %s", password)
code, _ = ftp.RawCmd("PASS %s", password)
if code == 230 {
code, _ = ftp.RawCmd("NOOP")
return
}
}
}
}
// Nothing strange... let's try a normal login
return ftp.Login(username, password)
}
*/

// login to the server
func (ftp *FTP) Login(username string, password string) (err error) {
if _, err = ftp.cmd("331", "USER %s", username); err != nil {
Expand Down Expand Up @@ -499,9 +587,11 @@ func Connect(addr string) (*FTP, error) {
writer := bufio.NewWriter(conn)
reader := bufio.NewReader(conn)

reader.ReadString('\n')
//reader.ReadString('\n')
object := &FTP{conn: conn, addr: addr, reader: reader, writer: writer, debug: false}
object.receive()

return &FTP{conn: conn, addr: addr, reader: reader, writer: writer, debug: false}, nil
return object, nil
}

// connect to server, debug is ON
Expand All @@ -518,9 +608,10 @@ func ConnectDbg(addr string) (*FTP, error) {

var line string

line, err = reader.ReadString('\n')
object := &FTP{conn: conn, addr: addr, reader: reader, writer: writer, debug: false}
line, _ = object.receive()

log.Print(line)

return &FTP{conn: conn, addr: addr, reader: reader, writer: writer, debug: true}, nil
return object, nil
}
58 changes: 58 additions & 0 deletions ftp_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package goftp

import "testing"

//import "fmt"

var goodServer string
var uglyServer string
var badServer string

func init() {
//ProFTPD 1.3.5 Server (Debian)
goodServer = "bo.mirror.garr.it:21"

//Symantec EMEA FTP Server
badServer = "ftp.packardbell.com:21"

//Unknown server
uglyServer = "ftp.musicbrainz.org:21"
}

func standard(host string) (msg string) {
var err error
var connection *FTP

if connection, err = Connect(host); err != nil {
return "Can't connect ->" + err.Error()
}
if err = connection.Login("anonymous", "anonymous"); err != nil {
return "Can't login ->" + err.Error()
}
if _, err = connection.List(""); err != nil {
return "Can't list ->" + err.Error()
}
connection.Close()
return ""
}

func TestLogin_good(t *testing.T) {
str := standard(goodServer)
if len(str) > 0 {
t.Error(str)
}
}

func TestLogin_bad(t *testing.T) {
str := standard(badServer)
if len(str) > 0 {
t.Error(str)
}
}

func TestLogin_ugly(t *testing.T) {
str := standard(uglyServer)
if len(str) > 0 {
t.Error(str)
}
}

0 comments on commit cfb8336

Please sign in to comment.