| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874 |
- package webdavd
- import (
- "context"
- "crypto/tls"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "os"
- "path"
- "path/filepath"
- "runtime"
- "testing"
- "time"
- "github.com/eikenb/pipeat"
- "github.com/stretchr/testify/assert"
- "github.com/drakkan/sftpgo/common"
- "github.com/drakkan/sftpgo/dataprovider"
- "github.com/drakkan/sftpgo/httpd"
- "github.com/drakkan/sftpgo/vfs"
- )
- const (
- configDir = ".."
- testFile = "test_dav_file"
- )
- var (
- errWalkDir = errors.New("err walk dir")
- errWalkFile = errors.New("err walk file")
- )
- // MockOsFs mockable OsFs
- type MockOsFs struct {
- vfs.Fs
- err error
- isAtomicUploadSupported bool
- }
- // Name returns the name for the Fs implementation
- func (fs MockOsFs) Name() string {
- return "mockOsFs"
- }
- // Open returns nil
- func (MockOsFs) Open(name string, offset int64) (*os.File, *pipeat.PipeReaderAt, func(), error) {
- return nil, nil, nil, nil
- }
- // IsUploadResumeSupported returns true if upload resume is supported
- func (MockOsFs) IsUploadResumeSupported() bool {
- return false
- }
- // IsAtomicUploadSupported returns true if atomic upload is supported
- func (fs MockOsFs) IsAtomicUploadSupported() bool {
- return fs.isAtomicUploadSupported
- }
- // Remove removes the named file or (empty) directory.
- func (fs MockOsFs) Remove(name string, isDir bool) error {
- if fs.err != nil {
- return fs.err
- }
- return os.Remove(name)
- }
- // Rename renames (moves) source to target
- func (fs MockOsFs) Rename(source, target string) error {
- if fs.err != nil {
- return fs.err
- }
- return os.Rename(source, target)
- }
- // Walk returns a duplicate path for testing
- func (fs MockOsFs) Walk(root string, walkFn filepath.WalkFunc) error {
- if fs.err == errWalkDir {
- walkFn("fsdpath", vfs.NewFileInfo("dpath", true, 0, time.Now(), false), nil) //nolint:errcheck
- walkFn("fsdpath", vfs.NewFileInfo("dpath", true, 0, time.Now(), false), nil) //nolint:errcheck
- return nil
- }
- walkFn("fsfpath", vfs.NewFileInfo("fpath", false, 0, time.Now(), false), nil) //nolint:errcheck
- return fs.err
- }
- // GetMimeType implements vfs.MimeTyper
- func (fs MockOsFs) GetMimeType(name string) (string, error) {
- return "application/octet-stream", nil
- }
- func newMockOsFs(err error, atomicUpload bool, connectionID, rootDir string) vfs.Fs {
- return &MockOsFs{
- Fs: vfs.NewOsFs(connectionID, rootDir, nil),
- err: err,
- isAtomicUploadSupported: atomicUpload,
- }
- }
- func TestOrderDirsToRemove(t *testing.T) {
- user := dataprovider.User{}
- fs := vfs.NewOsFs("id", os.TempDir(), nil)
- connection := &Connection{
- BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolWebDAV, user, fs),
- request: nil,
- }
- dirsToRemove := []objectMapping{}
- orderedDirs := connection.orderDirsToRemove(dirsToRemove)
- assert.Equal(t, len(dirsToRemove), len(orderedDirs))
- dirsToRemove = []objectMapping{
- {
- fsPath: "dir1",
- virtualPath: "",
- },
- }
- orderedDirs = connection.orderDirsToRemove(dirsToRemove)
- assert.Equal(t, len(dirsToRemove), len(orderedDirs))
- dirsToRemove = []objectMapping{
- {
- fsPath: "dir1",
- virtualPath: "",
- },
- {
- fsPath: "dir12",
- virtualPath: "",
- },
- {
- fsPath: filepath.Join("dir1", "a", "b"),
- virtualPath: "",
- },
- {
- fsPath: filepath.Join("dir1", "a"),
- virtualPath: "",
- },
- }
- orderedDirs = connection.orderDirsToRemove(dirsToRemove)
- if assert.Equal(t, len(dirsToRemove), len(orderedDirs)) {
- assert.Equal(t, "dir12", orderedDirs[0].fsPath)
- assert.Equal(t, filepath.Join("dir1", "a", "b"), orderedDirs[1].fsPath)
- assert.Equal(t, filepath.Join("dir1", "a"), orderedDirs[2].fsPath)
- assert.Equal(t, "dir1", orderedDirs[3].fsPath)
- }
- }
- func TestUserInvalidParams(t *testing.T) {
- u := dataprovider.User{
- Username: "username",
- HomeDir: "invalid",
- }
- c := &Configuration{
- BindPort: 9000,
- }
- server, err := newServer(c, configDir)
- assert.NoError(t, err)
- req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", u.Username), nil)
- assert.NoError(t, err)
- _, err = server.validateUser(u, req)
- if assert.Error(t, err) {
- assert.EqualError(t, err, fmt.Sprintf("cannot login user with invalid home dir: %#v", u.HomeDir))
- }
- u.HomeDir = filepath.Clean(os.TempDir())
- subDir := "subdir"
- mappedPath1 := filepath.Join(os.TempDir(), "vdir1")
- vdirPath1 := "/vdir1"
- mappedPath2 := filepath.Join(os.TempDir(), "vdir1", subDir)
- vdirPath2 := "/vdir2"
- u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
- BaseVirtualFolder: vfs.BaseVirtualFolder{
- MappedPath: mappedPath1,
- },
- VirtualPath: vdirPath1,
- })
- u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
- BaseVirtualFolder: vfs.BaseVirtualFolder{
- MappedPath: mappedPath2,
- },
- VirtualPath: vdirPath2,
- })
- _, err = server.validateUser(u, req)
- if assert.Error(t, err) {
- assert.EqualError(t, err, "overlapping mapped folders are allowed only with quota tracking disabled")
- }
- req.TLS = &tls.ConnectionState{}
- writeLog(req, nil)
- }
- func TestRemoteAddress(t *testing.T) {
- req, err := http.NewRequest(http.MethodGet, "/username", nil)
- assert.NoError(t, err)
- assert.Empty(t, req.RemoteAddr)
- remoteAddr1 := "100.100.100.100"
- remoteAddr2 := "172.172.172.172"
- req.Header.Set("X-Forwarded-For", remoteAddr1)
- checkRemoteAddress(req)
- assert.Equal(t, remoteAddr1, req.RemoteAddr)
- req.RemoteAddr = ""
- req.Header.Set("X-Forwarded-For", fmt.Sprintf("%v, %v", remoteAddr2, remoteAddr1))
- checkRemoteAddress(req)
- assert.Equal(t, remoteAddr2, req.RemoteAddr)
- req.Header.Del("X-Forwarded-For")
- req.RemoteAddr = ""
- req.Header.Set("X-Real-IP", remoteAddr1)
- checkRemoteAddress(req)
- assert.Equal(t, remoteAddr1, req.RemoteAddr)
- req.RemoteAddr = ""
- oldValue := common.Config.ProxyProtocol
- common.Config.ProxyProtocol = 1
- checkRemoteAddress(req)
- assert.Empty(t, req.RemoteAddr)
- common.Config.ProxyProtocol = oldValue
- }
- func TestConnWithNilRequest(t *testing.T) {
- c := &Connection{}
- assert.Empty(t, c.GetClientVersion())
- assert.Empty(t, c.GetCommand())
- assert.Empty(t, c.GetRemoteAddress())
- }
- func TestResolvePathErrors(t *testing.T) {
- ctx := context.Background()
- user := dataprovider.User{
- HomeDir: "invalid",
- }
- user.Permissions = make(map[string][]string)
- user.Permissions["/"] = []string{dataprovider.PermAny}
- fs := vfs.NewOsFs("connID", user.HomeDir, nil)
- connection := &Connection{
- BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolWebDAV, user, fs),
- }
- err := connection.Mkdir(ctx, "", os.ModePerm)
- if assert.Error(t, err) {
- assert.EqualError(t, err, common.ErrGenericFailure.Error())
- }
- err = connection.Rename(ctx, "oldName", "newName")
- if assert.Error(t, err) {
- assert.EqualError(t, err, common.ErrGenericFailure.Error())
- }
- _, err = connection.Stat(ctx, "name")
- if assert.Error(t, err) {
- assert.EqualError(t, err, common.ErrGenericFailure.Error())
- }
- err = connection.RemoveAll(ctx, "")
- if assert.Error(t, err) {
- assert.EqualError(t, err, common.ErrGenericFailure.Error())
- }
- _, err = connection.OpenFile(ctx, "", 0, os.ModePerm)
- if assert.Error(t, err) {
- assert.EqualError(t, err, common.ErrGenericFailure.Error())
- }
- if runtime.GOOS != "windows" {
- connection.User.HomeDir = filepath.Clean(os.TempDir())
- connection.Fs = vfs.NewOsFs("connID", connection.User.HomeDir, nil)
- subDir := "sub"
- testTxtFile := "file.txt"
- err = os.MkdirAll(filepath.Join(os.TempDir(), subDir, subDir), os.ModePerm)
- assert.NoError(t, err)
- err = ioutil.WriteFile(filepath.Join(os.TempDir(), subDir, subDir, testTxtFile), []byte("content"), os.ModePerm)
- assert.NoError(t, err)
- err = os.Chmod(filepath.Join(os.TempDir(), subDir, subDir), 0001)
- assert.NoError(t, err)
- err = connection.Rename(ctx, testTxtFile, path.Join(subDir, subDir, testTxtFile))
- if assert.Error(t, err) {
- assert.EqualError(t, err, common.ErrPermissionDenied.Error())
- }
- _, err = connection.putFile(filepath.Join(connection.User.HomeDir, subDir, subDir, testTxtFile),
- path.Join(subDir, subDir, testTxtFile))
- if assert.Error(t, err) {
- assert.EqualError(t, err, common.ErrPermissionDenied.Error())
- }
- err = os.Chmod(filepath.Join(os.TempDir(), subDir, subDir), os.ModePerm)
- assert.NoError(t, err)
- err = os.RemoveAll(filepath.Join(os.TempDir(), subDir))
- assert.NoError(t, err)
- }
- }
- func TestFileAccessErrors(t *testing.T) {
- ctx := context.Background()
- user := dataprovider.User{
- HomeDir: filepath.Clean(os.TempDir()),
- }
- user.Permissions = make(map[string][]string)
- user.Permissions["/"] = []string{dataprovider.PermAny}
- fs := vfs.NewOsFs("connID", user.HomeDir, nil)
- connection := &Connection{
- BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolWebDAV, user, fs),
- }
- missingPath := "missing path"
- fsMissingPath := filepath.Join(user.HomeDir, missingPath)
- err := connection.RemoveAll(ctx, missingPath)
- if assert.Error(t, err) {
- assert.EqualError(t, err, os.ErrNotExist.Error())
- }
- info := vfs.NewFileInfo(missingPath, true, 0, time.Now(), false)
- _, err = connection.getFile(fsMissingPath, missingPath, info)
- if assert.Error(t, err) {
- assert.EqualError(t, err, os.ErrNotExist.Error())
- }
- info = vfs.NewFileInfo(missingPath, false, 123, time.Now(), false)
- _, err = connection.getFile(fsMissingPath, missingPath, info)
- if assert.Error(t, err) {
- assert.EqualError(t, err, os.ErrNotExist.Error())
- }
- p := filepath.Join(user.HomeDir, "adir", missingPath)
- _, err = connection.handleUploadToNewFile(p, p, path.Join("adir", missingPath))
- if assert.Error(t, err) {
- assert.EqualError(t, err, os.ErrNotExist.Error())
- }
- _, err = connection.handleUploadToExistingFile(p, p, 0, path.Join("adir", missingPath))
- if assert.Error(t, err) {
- assert.EqualError(t, err, os.ErrNotExist.Error())
- }
- connection.Fs = newMockOsFs(nil, false, fs.ConnectionID(), user.HomeDir)
- _, err = connection.handleUploadToExistingFile(p, p, 0, path.Join("adir", missingPath))
- if assert.Error(t, err) {
- assert.EqualError(t, err, os.ErrNotExist.Error())
- }
- f, err := ioutil.TempFile("", "temp")
- assert.NoError(t, err)
- err = f.Close()
- assert.NoError(t, err)
- davFile, err := connection.handleUploadToExistingFile(f.Name(), f.Name(), 123, f.Name())
- if assert.NoError(t, err) {
- transfer := davFile.(*webDavFile)
- transfers := connection.GetTransfers()
- if assert.Equal(t, 1, len(transfers)) {
- assert.Equal(t, transfers[0].ID, transfer.GetID())
- assert.Equal(t, int64(123), transfer.InitialSize)
- err = transfer.Close()
- assert.NoError(t, err)
- assert.Equal(t, 0, len(connection.GetTransfers()))
- }
- }
- err = os.Remove(f.Name())
- assert.NoError(t, err)
- }
- func TestRemoveDirTree(t *testing.T) {
- user := dataprovider.User{
- HomeDir: filepath.Clean(os.TempDir()),
- }
- user.Permissions = make(map[string][]string)
- user.Permissions["/"] = []string{dataprovider.PermAny}
- fs := vfs.NewOsFs("connID", user.HomeDir, nil)
- connection := &Connection{
- BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolWebDAV, user, fs),
- }
- vpath := path.Join("adir", "missing")
- p := filepath.Join(user.HomeDir, "adir", "missing")
- err := connection.removeDirTree(p, vpath)
- if assert.Error(t, err) {
- assert.True(t, os.IsNotExist(err))
- }
- connection.Fs = newMockOsFs(nil, false, "mockID", user.HomeDir)
- err = connection.removeDirTree(p, vpath)
- if assert.Error(t, err) {
- assert.True(t, os.IsNotExist(err))
- }
- errFake := errors.New("fake err")
- connection.Fs = newMockOsFs(errFake, false, "mockID", user.HomeDir)
- err = connection.removeDirTree(p, vpath)
- if assert.Error(t, err) {
- assert.EqualError(t, err, errFake.Error())
- }
- connection.Fs = newMockOsFs(errWalkDir, true, "mockID", user.HomeDir)
- err = connection.removeDirTree(p, vpath)
- if assert.Error(t, err) {
- assert.True(t, os.IsNotExist(err))
- }
- connection.Fs = newMockOsFs(errWalkFile, false, "mockID", user.HomeDir)
- err = connection.removeDirTree(p, vpath)
- if assert.Error(t, err) {
- assert.EqualError(t, err, errWalkFile.Error())
- }
- connection.User.Permissions["/"] = []string{dataprovider.PermListItems}
- connection.Fs = newMockOsFs(nil, false, "mockID", user.HomeDir)
- err = connection.removeDirTree(p, vpath)
- if assert.Error(t, err) {
- assert.EqualError(t, err, common.ErrPermissionDenied.Error())
- }
- }
- func TestContentType(t *testing.T) {
- user := dataprovider.User{
- HomeDir: filepath.Clean(os.TempDir()),
- }
- user.Permissions = make(map[string][]string)
- user.Permissions["/"] = []string{dataprovider.PermAny}
- fs := vfs.NewOsFs("connID", user.HomeDir, nil)
- connection := &Connection{
- BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolWebDAV, user, fs),
- }
- testFilePath := filepath.Join(user.HomeDir, testFile)
- ctx := context.Background()
- baseTransfer := common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFile,
- common.TransferDownload, 0, 0, 0, false, fs)
- info := vfs.NewFileInfo(testFilePath, true, 0, time.Now(), false)
- davFile := newWebDavFile(baseTransfer, nil, nil, info)
- fi, err := davFile.Stat()
- if assert.NoError(t, err) {
- ctype, err := fi.(webDavFileInfo).ContentType(ctx)
- assert.NoError(t, err)
- assert.Equal(t, "inode/directory", ctype)
- }
- err = davFile.Close()
- assert.NoError(t, err)
- fs = newMockOsFs(nil, false, fs.ConnectionID(), user.GetHomeDir())
- err = ioutil.WriteFile(testFilePath, []byte(""), os.ModePerm)
- assert.NoError(t, err)
- fi, err = os.Stat(testFilePath)
- assert.NoError(t, err)
- davFile = newWebDavFile(baseTransfer, nil, nil, fi)
- davFile.Fs = fs
- fi, err = davFile.Stat()
- if assert.NoError(t, err) {
- ctype, err := fi.(webDavFileInfo).ContentType(ctx)
- assert.NoError(t, err)
- assert.Equal(t, "application/octet-stream", ctype)
- }
- _, err = davFile.Readdir(-1)
- assert.Error(t, err)
- err = davFile.Close()
- assert.NoError(t, err)
- err = os.Remove(testFilePath)
- assert.NoError(t, err)
- }
- func TestTransferReadWriteErrors(t *testing.T) {
- user := dataprovider.User{
- HomeDir: filepath.Clean(os.TempDir()),
- }
- user.Permissions = make(map[string][]string)
- user.Permissions["/"] = []string{dataprovider.PermAny}
- fs := vfs.NewOsFs("connID", user.HomeDir, nil)
- connection := &Connection{
- BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolWebDAV, user, fs),
- }
- testFilePath := filepath.Join(user.HomeDir, testFile)
- baseTransfer := common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFile,
- common.TransferUpload, 0, 0, 0, false, fs)
- davFile := newWebDavFile(baseTransfer, nil, nil, nil)
- assert.False(t, davFile.isDir())
- p := make([]byte, 1)
- _, err := davFile.Read(p)
- assert.EqualError(t, err, common.ErrOpUnsupported.Error())
- r, w, err := pipeat.Pipe()
- assert.NoError(t, err)
- davFile = newWebDavFile(baseTransfer, nil, r, nil)
- davFile.Connection.RemoveTransfer(davFile.BaseTransfer)
- davFile = newWebDavFile(baseTransfer, vfs.NewPipeWriter(w), nil, nil)
- davFile.Connection.RemoveTransfer(davFile.BaseTransfer)
- err = r.Close()
- assert.NoError(t, err)
- err = w.Close()
- assert.NoError(t, err)
- baseTransfer = common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFile,
- common.TransferDownload, 0, 0, 0, false, fs)
- davFile = newWebDavFile(baseTransfer, nil, nil, nil)
- _, err = davFile.Read(p)
- assert.True(t, os.IsNotExist(err))
- _, err = davFile.Stat()
- assert.True(t, os.IsNotExist(err))
- baseTransfer = common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFile,
- common.TransferDownload, 0, 0, 0, false, fs)
- err = ioutil.WriteFile(testFilePath, []byte(""), os.ModePerm)
- assert.NoError(t, err)
- f, err := os.Open(testFilePath)
- if assert.NoError(t, err) {
- err = f.Close()
- assert.NoError(t, err)
- }
- davFile = newWebDavFile(baseTransfer, nil, nil, nil)
- davFile.reader = f
- err = davFile.Close()
- assert.EqualError(t, err, common.ErrGenericFailure.Error())
- err = davFile.Close()
- assert.EqualError(t, err, common.ErrTransferClosed.Error())
- _, err = davFile.Read(p)
- assert.Error(t, err)
- info, err := davFile.Stat()
- if assert.NoError(t, err) {
- assert.Equal(t, int64(0), info.Size())
- }
- baseTransfer = common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFile,
- common.TransferDownload, 0, 0, 0, false, fs)
- davFile = newWebDavFile(baseTransfer, nil, nil, nil)
- davFile.writer = f
- err = davFile.Close()
- assert.EqualError(t, err, common.ErrGenericFailure.Error())
- err = os.Remove(testFilePath)
- assert.NoError(t, err)
- }
- func TestTransferSeek(t *testing.T) {
- user := dataprovider.User{
- HomeDir: filepath.Clean(os.TempDir()),
- }
- user.Permissions = make(map[string][]string)
- user.Permissions["/"] = []string{dataprovider.PermAny}
- fs := vfs.NewOsFs("connID", user.HomeDir, nil)
- connection := &Connection{
- BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolWebDAV, user, fs),
- }
- testFilePath := filepath.Join(user.HomeDir, testFile)
- baseTransfer := common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFile,
- common.TransferUpload, 0, 0, 0, false, fs)
- davFile := newWebDavFile(baseTransfer, nil, nil, nil)
- _, err := davFile.Seek(0, io.SeekStart)
- assert.EqualError(t, err, common.ErrOpUnsupported.Error())
- err = davFile.Close()
- assert.NoError(t, err)
- baseTransfer = common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFile,
- common.TransferDownload, 0, 0, 0, false, fs)
- davFile = newWebDavFile(baseTransfer, nil, nil, nil)
- _, err = davFile.Seek(0, io.SeekCurrent)
- assert.True(t, os.IsNotExist(err))
- davFile.Connection.RemoveTransfer(davFile.BaseTransfer)
- err = ioutil.WriteFile(testFilePath, []byte("content"), os.ModePerm)
- assert.NoError(t, err)
- f, err := os.Open(testFilePath)
- if assert.NoError(t, err) {
- err = f.Close()
- assert.NoError(t, err)
- }
- baseTransfer = common.NewBaseTransfer(f, connection.BaseConnection, nil, testFilePath, testFile,
- common.TransferDownload, 0, 0, 0, false, fs)
- davFile = newWebDavFile(baseTransfer, nil, nil, nil)
- _, err = davFile.Seek(0, io.SeekStart)
- assert.Error(t, err)
- davFile.Connection.RemoveTransfer(davFile.BaseTransfer)
- baseTransfer = common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFile,
- common.TransferDownload, 0, 0, 0, false, fs)
- davFile = newWebDavFile(baseTransfer, nil, nil, nil)
- davFile.reader = f
- res, err := davFile.Seek(0, io.SeekStart)
- assert.NoError(t, err)
- assert.Equal(t, int64(0), res)
- davFile.Connection.RemoveTransfer(davFile.BaseTransfer)
- info, err := os.Stat(testFilePath)
- assert.NoError(t, err)
- davFile = newWebDavFile(baseTransfer, nil, nil, info)
- davFile.reader = f
- res, err = davFile.Seek(0, io.SeekEnd)
- assert.NoError(t, err)
- assert.Equal(t, int64(7), res)
- davFile = newWebDavFile(baseTransfer, nil, nil, info)
- davFile.reader = f
- davFile.Fs = newMockOsFs(nil, true, fs.ConnectionID(), user.GetHomeDir())
- res, err = davFile.Seek(2, io.SeekStart)
- assert.NoError(t, err)
- assert.Equal(t, int64(2), res)
- davFile = newWebDavFile(baseTransfer, nil, nil, info)
- davFile.Fs = newMockOsFs(nil, true, fs.ConnectionID(), user.GetHomeDir())
- res, err = davFile.Seek(2, io.SeekEnd)
- assert.NoError(t, err)
- assert.Equal(t, int64(5), res)
- davFile = newWebDavFile(baseTransfer, nil, nil, nil)
- res, err = davFile.Seek(2, io.SeekEnd)
- assert.EqualError(t, err, "unable to get file size, seek from end not possible")
- assert.Equal(t, int64(0), res)
- assert.Len(t, common.Connections.GetStats(), 0)
- err = os.Remove(testFilePath)
- assert.NoError(t, err)
- }
- func TestBasicUsersCache(t *testing.T) {
- username := "webdav_internal_test"
- password := "pwd"
- u := dataprovider.User{
- Username: username,
- Password: password,
- HomeDir: filepath.Join(os.TempDir(), username),
- Status: 1,
- ExpirationDate: 0,
- }
- u.Permissions = make(map[string][]string)
- u.Permissions["/"] = []string{dataprovider.PermAny}
- user, _, err := httpd.AddUser(u, http.StatusOK)
- assert.NoError(t, err)
- c := &Configuration{
- BindPort: 9000,
- Cache: Cache{
- Enabled: true,
- MaxSize: 50,
- ExpirationTime: 1,
- },
- }
- server, err := newServer(c, configDir)
- assert.NoError(t, err)
- req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user.Username), nil)
- assert.NoError(t, err)
- _, _, err = server.authenticate(req)
- assert.Error(t, err)
- now := time.Now()
- req.SetBasicAuth(username, password)
- _, isCached, err := server.authenticate(req)
- assert.NoError(t, err)
- assert.False(t, isCached)
- // now the user should be cached
- var cachedUser dataprovider.CachedUser
- result, ok := dataprovider.GetCachedWebDAVUser(username)
- if assert.True(t, ok) {
- cachedUser = result.(dataprovider.CachedUser)
- assert.False(t, cachedUser.IsExpired())
- assert.True(t, cachedUser.Expiration.After(now.Add(time.Duration(c.Cache.ExpirationTime)*time.Minute)))
- // authenticate must return the cached user now
- authUser, isCached, err := server.authenticate(req)
- assert.NoError(t, err)
- assert.True(t, isCached)
- assert.Equal(t, cachedUser.User, authUser)
- }
- // a wrong password must fail
- req.SetBasicAuth(username, "wrong")
- _, _, err = server.authenticate(req)
- assert.EqualError(t, err, dataprovider.ErrInvalidCredentials.Error())
- req.SetBasicAuth(username, password)
- // force cached user expiration
- cachedUser.Expiration = now
- dataprovider.CacheWebDAVUser(cachedUser, c.Cache.MaxSize)
- result, ok = dataprovider.GetCachedWebDAVUser(username)
- if assert.True(t, ok) {
- cachedUser = result.(dataprovider.CachedUser)
- assert.True(t, cachedUser.IsExpired())
- }
- // now authenticate should get the user from the data provider and update the cache
- _, isCached, err = server.authenticate(req)
- assert.NoError(t, err)
- assert.False(t, isCached)
- result, ok = dataprovider.GetCachedWebDAVUser(username)
- if assert.True(t, ok) {
- cachedUser = result.(dataprovider.CachedUser)
- assert.False(t, cachedUser.IsExpired())
- }
- // cache is invalidated after a user modification
- user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
- assert.NoError(t, err)
- _, ok = dataprovider.GetCachedWebDAVUser(username)
- assert.False(t, ok)
- _, isCached, err = server.authenticate(req)
- assert.NoError(t, err)
- assert.False(t, isCached)
- _, ok = dataprovider.GetCachedWebDAVUser(username)
- assert.True(t, ok)
- // cache is invalidated after user deletion
- _, err = httpd.RemoveUser(user, http.StatusOK)
- assert.NoError(t, err)
- _, ok = dataprovider.GetCachedWebDAVUser(username)
- assert.False(t, ok)
- }
- func TestUsersCacheSizeAndExpiration(t *testing.T) {
- username := "webdav_internal_test"
- password := "pwd"
- u := dataprovider.User{
- HomeDir: filepath.Join(os.TempDir(), username),
- Status: 1,
- ExpirationDate: 0,
- }
- u.Username = username + "1"
- u.Password = password + "1"
- u.Permissions = make(map[string][]string)
- u.Permissions["/"] = []string{dataprovider.PermAny}
- user1, _, err := httpd.AddUser(u, http.StatusOK)
- assert.NoError(t, err)
- u.Username = username + "2"
- u.Password = password + "2"
- user2, _, err := httpd.AddUser(u, http.StatusOK)
- assert.NoError(t, err)
- u.Username = username + "3"
- u.Password = password + "3"
- user3, _, err := httpd.AddUser(u, http.StatusOK)
- assert.NoError(t, err)
- u.Username = username + "4"
- u.Password = password + "4"
- user4, _, err := httpd.AddUser(u, http.StatusOK)
- assert.NoError(t, err)
- c := &Configuration{
- BindPort: 9000,
- Cache: Cache{
- Enabled: true,
- MaxSize: 3,
- ExpirationTime: 1,
- },
- }
- server, err := newServer(c, configDir)
- assert.NoError(t, err)
- req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user1.Username), nil)
- assert.NoError(t, err)
- req.SetBasicAuth(user1.Username, password+"1")
- _, isCached, err := server.authenticate(req)
- assert.NoError(t, err)
- assert.False(t, isCached)
- req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user2.Username), nil)
- assert.NoError(t, err)
- req.SetBasicAuth(user2.Username, password+"2")
- _, isCached, err = server.authenticate(req)
- assert.NoError(t, err)
- assert.False(t, isCached)
- req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user3.Username), nil)
- assert.NoError(t, err)
- req.SetBasicAuth(user3.Username, password+"3")
- _, isCached, err = server.authenticate(req)
- assert.NoError(t, err)
- assert.False(t, isCached)
- // the first 3 users are now cached
- _, ok := dataprovider.GetCachedWebDAVUser(user1.Username)
- assert.True(t, ok)
- _, ok = dataprovider.GetCachedWebDAVUser(user2.Username)
- assert.True(t, ok)
- _, ok = dataprovider.GetCachedWebDAVUser(user3.Username)
- assert.True(t, ok)
- req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user4.Username), nil)
- assert.NoError(t, err)
- req.SetBasicAuth(user4.Username, password+"4")
- _, isCached, err = server.authenticate(req)
- assert.NoError(t, err)
- assert.False(t, isCached)
- // user1, the first cached, should be removed now
- _, ok = dataprovider.GetCachedWebDAVUser(user1.Username)
- assert.False(t, ok)
- _, ok = dataprovider.GetCachedWebDAVUser(user2.Username)
- assert.True(t, ok)
- _, ok = dataprovider.GetCachedWebDAVUser(user3.Username)
- assert.True(t, ok)
- _, ok = dataprovider.GetCachedWebDAVUser(user4.Username)
- assert.True(t, ok)
- // user1 logins, user2 should be removed
- req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user1.Username), nil)
- assert.NoError(t, err)
- req.SetBasicAuth(user1.Username, password+"1")
- _, isCached, err = server.authenticate(req)
- assert.NoError(t, err)
- assert.False(t, isCached)
- _, ok = dataprovider.GetCachedWebDAVUser(user2.Username)
- assert.False(t, ok)
- _, ok = dataprovider.GetCachedWebDAVUser(user1.Username)
- assert.True(t, ok)
- _, ok = dataprovider.GetCachedWebDAVUser(user3.Username)
- assert.True(t, ok)
- _, ok = dataprovider.GetCachedWebDAVUser(user4.Username)
- assert.True(t, ok)
- // user2 logins, user3 should be removed
- req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user2.Username), nil)
- assert.NoError(t, err)
- req.SetBasicAuth(user2.Username, password+"2")
- _, isCached, err = server.authenticate(req)
- assert.NoError(t, err)
- assert.False(t, isCached)
- _, ok = dataprovider.GetCachedWebDAVUser(user3.Username)
- assert.False(t, ok)
- _, ok = dataprovider.GetCachedWebDAVUser(user1.Username)
- assert.True(t, ok)
- _, ok = dataprovider.GetCachedWebDAVUser(user2.Username)
- assert.True(t, ok)
- _, ok = dataprovider.GetCachedWebDAVUser(user4.Username)
- assert.True(t, ok)
- // user3 logins, user4 should be removed
- req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user3.Username), nil)
- assert.NoError(t, err)
- req.SetBasicAuth(user3.Username, password+"3")
- _, isCached, err = server.authenticate(req)
- assert.NoError(t, err)
- assert.False(t, isCached)
- _, ok = dataprovider.GetCachedWebDAVUser(user4.Username)
- assert.False(t, ok)
- _, ok = dataprovider.GetCachedWebDAVUser(user1.Username)
- assert.True(t, ok)
- _, ok = dataprovider.GetCachedWebDAVUser(user2.Username)
- assert.True(t, ok)
- _, ok = dataprovider.GetCachedWebDAVUser(user3.Username)
- assert.True(t, ok)
- // now remove user1 after an update
- user1, _, err = httpd.UpdateUser(user1, http.StatusOK, "")
- assert.NoError(t, err)
- _, ok = dataprovider.GetCachedWebDAVUser(user1.Username)
- assert.False(t, ok)
- req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user4.Username), nil)
- assert.NoError(t, err)
- req.SetBasicAuth(user4.Username, password+"4")
- _, isCached, err = server.authenticate(req)
- assert.NoError(t, err)
- assert.False(t, isCached)
- req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user1.Username), nil)
- assert.NoError(t, err)
- req.SetBasicAuth(user1.Username, password+"1")
- _, isCached, err = server.authenticate(req)
- assert.NoError(t, err)
- assert.False(t, isCached)
- _, ok = dataprovider.GetCachedWebDAVUser(user2.Username)
- assert.False(t, ok)
- _, ok = dataprovider.GetCachedWebDAVUser(user1.Username)
- assert.True(t, ok)
- _, ok = dataprovider.GetCachedWebDAVUser(user3.Username)
- assert.True(t, ok)
- _, ok = dataprovider.GetCachedWebDAVUser(user4.Username)
- assert.True(t, ok)
- _, err = httpd.RemoveUser(user1, http.StatusOK)
- assert.NoError(t, err)
- _, err = httpd.RemoveUser(user2, http.StatusOK)
- assert.NoError(t, err)
- _, err = httpd.RemoveUser(user3, http.StatusOK)
- assert.NoError(t, err)
- _, err = httpd.RemoveUser(user4, http.StatusOK)
- assert.NoError(t, err)
- }
|