internal_test.go 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874
  1. package webdavd
  2. import (
  3. "context"
  4. "crypto/tls"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "io/ioutil"
  9. "net/http"
  10. "os"
  11. "path"
  12. "path/filepath"
  13. "runtime"
  14. "testing"
  15. "time"
  16. "github.com/eikenb/pipeat"
  17. "github.com/stretchr/testify/assert"
  18. "github.com/drakkan/sftpgo/common"
  19. "github.com/drakkan/sftpgo/dataprovider"
  20. "github.com/drakkan/sftpgo/httpd"
  21. "github.com/drakkan/sftpgo/vfs"
  22. )
  23. const (
  24. configDir = ".."
  25. testFile = "test_dav_file"
  26. )
  27. var (
  28. errWalkDir = errors.New("err walk dir")
  29. errWalkFile = errors.New("err walk file")
  30. )
  31. // MockOsFs mockable OsFs
  32. type MockOsFs struct {
  33. vfs.Fs
  34. err error
  35. isAtomicUploadSupported bool
  36. }
  37. // Name returns the name for the Fs implementation
  38. func (fs MockOsFs) Name() string {
  39. return "mockOsFs"
  40. }
  41. // Open returns nil
  42. func (MockOsFs) Open(name string, offset int64) (*os.File, *pipeat.PipeReaderAt, func(), error) {
  43. return nil, nil, nil, nil
  44. }
  45. // IsUploadResumeSupported returns true if upload resume is supported
  46. func (MockOsFs) IsUploadResumeSupported() bool {
  47. return false
  48. }
  49. // IsAtomicUploadSupported returns true if atomic upload is supported
  50. func (fs MockOsFs) IsAtomicUploadSupported() bool {
  51. return fs.isAtomicUploadSupported
  52. }
  53. // Remove removes the named file or (empty) directory.
  54. func (fs MockOsFs) Remove(name string, isDir bool) error {
  55. if fs.err != nil {
  56. return fs.err
  57. }
  58. return os.Remove(name)
  59. }
  60. // Rename renames (moves) source to target
  61. func (fs MockOsFs) Rename(source, target string) error {
  62. if fs.err != nil {
  63. return fs.err
  64. }
  65. return os.Rename(source, target)
  66. }
  67. // Walk returns a duplicate path for testing
  68. func (fs MockOsFs) Walk(root string, walkFn filepath.WalkFunc) error {
  69. if fs.err == errWalkDir {
  70. walkFn("fsdpath", vfs.NewFileInfo("dpath", true, 0, time.Now(), false), nil) //nolint:errcheck
  71. walkFn("fsdpath", vfs.NewFileInfo("dpath", true, 0, time.Now(), false), nil) //nolint:errcheck
  72. return nil
  73. }
  74. walkFn("fsfpath", vfs.NewFileInfo("fpath", false, 0, time.Now(), false), nil) //nolint:errcheck
  75. return fs.err
  76. }
  77. // GetMimeType implements vfs.MimeTyper
  78. func (fs MockOsFs) GetMimeType(name string) (string, error) {
  79. return "application/octet-stream", nil
  80. }
  81. func newMockOsFs(err error, atomicUpload bool, connectionID, rootDir string) vfs.Fs {
  82. return &MockOsFs{
  83. Fs: vfs.NewOsFs(connectionID, rootDir, nil),
  84. err: err,
  85. isAtomicUploadSupported: atomicUpload,
  86. }
  87. }
  88. func TestOrderDirsToRemove(t *testing.T) {
  89. user := dataprovider.User{}
  90. fs := vfs.NewOsFs("id", os.TempDir(), nil)
  91. connection := &Connection{
  92. BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolWebDAV, user, fs),
  93. request: nil,
  94. }
  95. dirsToRemove := []objectMapping{}
  96. orderedDirs := connection.orderDirsToRemove(dirsToRemove)
  97. assert.Equal(t, len(dirsToRemove), len(orderedDirs))
  98. dirsToRemove = []objectMapping{
  99. {
  100. fsPath: "dir1",
  101. virtualPath: "",
  102. },
  103. }
  104. orderedDirs = connection.orderDirsToRemove(dirsToRemove)
  105. assert.Equal(t, len(dirsToRemove), len(orderedDirs))
  106. dirsToRemove = []objectMapping{
  107. {
  108. fsPath: "dir1",
  109. virtualPath: "",
  110. },
  111. {
  112. fsPath: "dir12",
  113. virtualPath: "",
  114. },
  115. {
  116. fsPath: filepath.Join("dir1", "a", "b"),
  117. virtualPath: "",
  118. },
  119. {
  120. fsPath: filepath.Join("dir1", "a"),
  121. virtualPath: "",
  122. },
  123. }
  124. orderedDirs = connection.orderDirsToRemove(dirsToRemove)
  125. if assert.Equal(t, len(dirsToRemove), len(orderedDirs)) {
  126. assert.Equal(t, "dir12", orderedDirs[0].fsPath)
  127. assert.Equal(t, filepath.Join("dir1", "a", "b"), orderedDirs[1].fsPath)
  128. assert.Equal(t, filepath.Join("dir1", "a"), orderedDirs[2].fsPath)
  129. assert.Equal(t, "dir1", orderedDirs[3].fsPath)
  130. }
  131. }
  132. func TestUserInvalidParams(t *testing.T) {
  133. u := dataprovider.User{
  134. Username: "username",
  135. HomeDir: "invalid",
  136. }
  137. c := &Configuration{
  138. BindPort: 9000,
  139. }
  140. server, err := newServer(c, configDir)
  141. assert.NoError(t, err)
  142. req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", u.Username), nil)
  143. assert.NoError(t, err)
  144. _, err = server.validateUser(u, req)
  145. if assert.Error(t, err) {
  146. assert.EqualError(t, err, fmt.Sprintf("cannot login user with invalid home dir: %#v", u.HomeDir))
  147. }
  148. u.HomeDir = filepath.Clean(os.TempDir())
  149. subDir := "subdir"
  150. mappedPath1 := filepath.Join(os.TempDir(), "vdir1")
  151. vdirPath1 := "/vdir1"
  152. mappedPath2 := filepath.Join(os.TempDir(), "vdir1", subDir)
  153. vdirPath2 := "/vdir2"
  154. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  155. BaseVirtualFolder: vfs.BaseVirtualFolder{
  156. MappedPath: mappedPath1,
  157. },
  158. VirtualPath: vdirPath1,
  159. })
  160. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  161. BaseVirtualFolder: vfs.BaseVirtualFolder{
  162. MappedPath: mappedPath2,
  163. },
  164. VirtualPath: vdirPath2,
  165. })
  166. _, err = server.validateUser(u, req)
  167. if assert.Error(t, err) {
  168. assert.EqualError(t, err, "overlapping mapped folders are allowed only with quota tracking disabled")
  169. }
  170. req.TLS = &tls.ConnectionState{}
  171. writeLog(req, nil)
  172. }
  173. func TestRemoteAddress(t *testing.T) {
  174. req, err := http.NewRequest(http.MethodGet, "/username", nil)
  175. assert.NoError(t, err)
  176. assert.Empty(t, req.RemoteAddr)
  177. remoteAddr1 := "100.100.100.100"
  178. remoteAddr2 := "172.172.172.172"
  179. req.Header.Set("X-Forwarded-For", remoteAddr1)
  180. checkRemoteAddress(req)
  181. assert.Equal(t, remoteAddr1, req.RemoteAddr)
  182. req.RemoteAddr = ""
  183. req.Header.Set("X-Forwarded-For", fmt.Sprintf("%v, %v", remoteAddr2, remoteAddr1))
  184. checkRemoteAddress(req)
  185. assert.Equal(t, remoteAddr2, req.RemoteAddr)
  186. req.Header.Del("X-Forwarded-For")
  187. req.RemoteAddr = ""
  188. req.Header.Set("X-Real-IP", remoteAddr1)
  189. checkRemoteAddress(req)
  190. assert.Equal(t, remoteAddr1, req.RemoteAddr)
  191. req.RemoteAddr = ""
  192. oldValue := common.Config.ProxyProtocol
  193. common.Config.ProxyProtocol = 1
  194. checkRemoteAddress(req)
  195. assert.Empty(t, req.RemoteAddr)
  196. common.Config.ProxyProtocol = oldValue
  197. }
  198. func TestConnWithNilRequest(t *testing.T) {
  199. c := &Connection{}
  200. assert.Empty(t, c.GetClientVersion())
  201. assert.Empty(t, c.GetCommand())
  202. assert.Empty(t, c.GetRemoteAddress())
  203. }
  204. func TestResolvePathErrors(t *testing.T) {
  205. ctx := context.Background()
  206. user := dataprovider.User{
  207. HomeDir: "invalid",
  208. }
  209. user.Permissions = make(map[string][]string)
  210. user.Permissions["/"] = []string{dataprovider.PermAny}
  211. fs := vfs.NewOsFs("connID", user.HomeDir, nil)
  212. connection := &Connection{
  213. BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolWebDAV, user, fs),
  214. }
  215. err := connection.Mkdir(ctx, "", os.ModePerm)
  216. if assert.Error(t, err) {
  217. assert.EqualError(t, err, common.ErrGenericFailure.Error())
  218. }
  219. err = connection.Rename(ctx, "oldName", "newName")
  220. if assert.Error(t, err) {
  221. assert.EqualError(t, err, common.ErrGenericFailure.Error())
  222. }
  223. _, err = connection.Stat(ctx, "name")
  224. if assert.Error(t, err) {
  225. assert.EqualError(t, err, common.ErrGenericFailure.Error())
  226. }
  227. err = connection.RemoveAll(ctx, "")
  228. if assert.Error(t, err) {
  229. assert.EqualError(t, err, common.ErrGenericFailure.Error())
  230. }
  231. _, err = connection.OpenFile(ctx, "", 0, os.ModePerm)
  232. if assert.Error(t, err) {
  233. assert.EqualError(t, err, common.ErrGenericFailure.Error())
  234. }
  235. if runtime.GOOS != "windows" {
  236. connection.User.HomeDir = filepath.Clean(os.TempDir())
  237. connection.Fs = vfs.NewOsFs("connID", connection.User.HomeDir, nil)
  238. subDir := "sub"
  239. testTxtFile := "file.txt"
  240. err = os.MkdirAll(filepath.Join(os.TempDir(), subDir, subDir), os.ModePerm)
  241. assert.NoError(t, err)
  242. err = ioutil.WriteFile(filepath.Join(os.TempDir(), subDir, subDir, testTxtFile), []byte("content"), os.ModePerm)
  243. assert.NoError(t, err)
  244. err = os.Chmod(filepath.Join(os.TempDir(), subDir, subDir), 0001)
  245. assert.NoError(t, err)
  246. err = connection.Rename(ctx, testTxtFile, path.Join(subDir, subDir, testTxtFile))
  247. if assert.Error(t, err) {
  248. assert.EqualError(t, err, common.ErrPermissionDenied.Error())
  249. }
  250. _, err = connection.putFile(filepath.Join(connection.User.HomeDir, subDir, subDir, testTxtFile),
  251. path.Join(subDir, subDir, testTxtFile))
  252. if assert.Error(t, err) {
  253. assert.EqualError(t, err, common.ErrPermissionDenied.Error())
  254. }
  255. err = os.Chmod(filepath.Join(os.TempDir(), subDir, subDir), os.ModePerm)
  256. assert.NoError(t, err)
  257. err = os.RemoveAll(filepath.Join(os.TempDir(), subDir))
  258. assert.NoError(t, err)
  259. }
  260. }
  261. func TestFileAccessErrors(t *testing.T) {
  262. ctx := context.Background()
  263. user := dataprovider.User{
  264. HomeDir: filepath.Clean(os.TempDir()),
  265. }
  266. user.Permissions = make(map[string][]string)
  267. user.Permissions["/"] = []string{dataprovider.PermAny}
  268. fs := vfs.NewOsFs("connID", user.HomeDir, nil)
  269. connection := &Connection{
  270. BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolWebDAV, user, fs),
  271. }
  272. missingPath := "missing path"
  273. fsMissingPath := filepath.Join(user.HomeDir, missingPath)
  274. err := connection.RemoveAll(ctx, missingPath)
  275. if assert.Error(t, err) {
  276. assert.EqualError(t, err, os.ErrNotExist.Error())
  277. }
  278. info := vfs.NewFileInfo(missingPath, true, 0, time.Now(), false)
  279. _, err = connection.getFile(fsMissingPath, missingPath, info)
  280. if assert.Error(t, err) {
  281. assert.EqualError(t, err, os.ErrNotExist.Error())
  282. }
  283. info = vfs.NewFileInfo(missingPath, false, 123, time.Now(), false)
  284. _, err = connection.getFile(fsMissingPath, missingPath, info)
  285. if assert.Error(t, err) {
  286. assert.EqualError(t, err, os.ErrNotExist.Error())
  287. }
  288. p := filepath.Join(user.HomeDir, "adir", missingPath)
  289. _, err = connection.handleUploadToNewFile(p, p, path.Join("adir", missingPath))
  290. if assert.Error(t, err) {
  291. assert.EqualError(t, err, os.ErrNotExist.Error())
  292. }
  293. _, err = connection.handleUploadToExistingFile(p, p, 0, path.Join("adir", missingPath))
  294. if assert.Error(t, err) {
  295. assert.EqualError(t, err, os.ErrNotExist.Error())
  296. }
  297. connection.Fs = newMockOsFs(nil, false, fs.ConnectionID(), user.HomeDir)
  298. _, err = connection.handleUploadToExistingFile(p, p, 0, path.Join("adir", missingPath))
  299. if assert.Error(t, err) {
  300. assert.EqualError(t, err, os.ErrNotExist.Error())
  301. }
  302. f, err := ioutil.TempFile("", "temp")
  303. assert.NoError(t, err)
  304. err = f.Close()
  305. assert.NoError(t, err)
  306. davFile, err := connection.handleUploadToExistingFile(f.Name(), f.Name(), 123, f.Name())
  307. if assert.NoError(t, err) {
  308. transfer := davFile.(*webDavFile)
  309. transfers := connection.GetTransfers()
  310. if assert.Equal(t, 1, len(transfers)) {
  311. assert.Equal(t, transfers[0].ID, transfer.GetID())
  312. assert.Equal(t, int64(123), transfer.InitialSize)
  313. err = transfer.Close()
  314. assert.NoError(t, err)
  315. assert.Equal(t, 0, len(connection.GetTransfers()))
  316. }
  317. }
  318. err = os.Remove(f.Name())
  319. assert.NoError(t, err)
  320. }
  321. func TestRemoveDirTree(t *testing.T) {
  322. user := dataprovider.User{
  323. HomeDir: filepath.Clean(os.TempDir()),
  324. }
  325. user.Permissions = make(map[string][]string)
  326. user.Permissions["/"] = []string{dataprovider.PermAny}
  327. fs := vfs.NewOsFs("connID", user.HomeDir, nil)
  328. connection := &Connection{
  329. BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolWebDAV, user, fs),
  330. }
  331. vpath := path.Join("adir", "missing")
  332. p := filepath.Join(user.HomeDir, "adir", "missing")
  333. err := connection.removeDirTree(p, vpath)
  334. if assert.Error(t, err) {
  335. assert.True(t, os.IsNotExist(err))
  336. }
  337. connection.Fs = newMockOsFs(nil, false, "mockID", user.HomeDir)
  338. err = connection.removeDirTree(p, vpath)
  339. if assert.Error(t, err) {
  340. assert.True(t, os.IsNotExist(err))
  341. }
  342. errFake := errors.New("fake err")
  343. connection.Fs = newMockOsFs(errFake, false, "mockID", user.HomeDir)
  344. err = connection.removeDirTree(p, vpath)
  345. if assert.Error(t, err) {
  346. assert.EqualError(t, err, errFake.Error())
  347. }
  348. connection.Fs = newMockOsFs(errWalkDir, true, "mockID", user.HomeDir)
  349. err = connection.removeDirTree(p, vpath)
  350. if assert.Error(t, err) {
  351. assert.True(t, os.IsNotExist(err))
  352. }
  353. connection.Fs = newMockOsFs(errWalkFile, false, "mockID", user.HomeDir)
  354. err = connection.removeDirTree(p, vpath)
  355. if assert.Error(t, err) {
  356. assert.EqualError(t, err, errWalkFile.Error())
  357. }
  358. connection.User.Permissions["/"] = []string{dataprovider.PermListItems}
  359. connection.Fs = newMockOsFs(nil, false, "mockID", user.HomeDir)
  360. err = connection.removeDirTree(p, vpath)
  361. if assert.Error(t, err) {
  362. assert.EqualError(t, err, common.ErrPermissionDenied.Error())
  363. }
  364. }
  365. func TestContentType(t *testing.T) {
  366. user := dataprovider.User{
  367. HomeDir: filepath.Clean(os.TempDir()),
  368. }
  369. user.Permissions = make(map[string][]string)
  370. user.Permissions["/"] = []string{dataprovider.PermAny}
  371. fs := vfs.NewOsFs("connID", user.HomeDir, nil)
  372. connection := &Connection{
  373. BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolWebDAV, user, fs),
  374. }
  375. testFilePath := filepath.Join(user.HomeDir, testFile)
  376. ctx := context.Background()
  377. baseTransfer := common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFile,
  378. common.TransferDownload, 0, 0, 0, false, fs)
  379. info := vfs.NewFileInfo(testFilePath, true, 0, time.Now(), false)
  380. davFile := newWebDavFile(baseTransfer, nil, nil, info)
  381. fi, err := davFile.Stat()
  382. if assert.NoError(t, err) {
  383. ctype, err := fi.(webDavFileInfo).ContentType(ctx)
  384. assert.NoError(t, err)
  385. assert.Equal(t, "inode/directory", ctype)
  386. }
  387. err = davFile.Close()
  388. assert.NoError(t, err)
  389. fs = newMockOsFs(nil, false, fs.ConnectionID(), user.GetHomeDir())
  390. err = ioutil.WriteFile(testFilePath, []byte(""), os.ModePerm)
  391. assert.NoError(t, err)
  392. fi, err = os.Stat(testFilePath)
  393. assert.NoError(t, err)
  394. davFile = newWebDavFile(baseTransfer, nil, nil, fi)
  395. davFile.Fs = fs
  396. fi, err = davFile.Stat()
  397. if assert.NoError(t, err) {
  398. ctype, err := fi.(webDavFileInfo).ContentType(ctx)
  399. assert.NoError(t, err)
  400. assert.Equal(t, "application/octet-stream", ctype)
  401. }
  402. _, err = davFile.Readdir(-1)
  403. assert.Error(t, err)
  404. err = davFile.Close()
  405. assert.NoError(t, err)
  406. err = os.Remove(testFilePath)
  407. assert.NoError(t, err)
  408. }
  409. func TestTransferReadWriteErrors(t *testing.T) {
  410. user := dataprovider.User{
  411. HomeDir: filepath.Clean(os.TempDir()),
  412. }
  413. user.Permissions = make(map[string][]string)
  414. user.Permissions["/"] = []string{dataprovider.PermAny}
  415. fs := vfs.NewOsFs("connID", user.HomeDir, nil)
  416. connection := &Connection{
  417. BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolWebDAV, user, fs),
  418. }
  419. testFilePath := filepath.Join(user.HomeDir, testFile)
  420. baseTransfer := common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFile,
  421. common.TransferUpload, 0, 0, 0, false, fs)
  422. davFile := newWebDavFile(baseTransfer, nil, nil, nil)
  423. assert.False(t, davFile.isDir())
  424. p := make([]byte, 1)
  425. _, err := davFile.Read(p)
  426. assert.EqualError(t, err, common.ErrOpUnsupported.Error())
  427. r, w, err := pipeat.Pipe()
  428. assert.NoError(t, err)
  429. davFile = newWebDavFile(baseTransfer, nil, r, nil)
  430. davFile.Connection.RemoveTransfer(davFile.BaseTransfer)
  431. davFile = newWebDavFile(baseTransfer, vfs.NewPipeWriter(w), nil, nil)
  432. davFile.Connection.RemoveTransfer(davFile.BaseTransfer)
  433. err = r.Close()
  434. assert.NoError(t, err)
  435. err = w.Close()
  436. assert.NoError(t, err)
  437. baseTransfer = common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFile,
  438. common.TransferDownload, 0, 0, 0, false, fs)
  439. davFile = newWebDavFile(baseTransfer, nil, nil, nil)
  440. _, err = davFile.Read(p)
  441. assert.True(t, os.IsNotExist(err))
  442. _, err = davFile.Stat()
  443. assert.True(t, os.IsNotExist(err))
  444. baseTransfer = common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFile,
  445. common.TransferDownload, 0, 0, 0, false, fs)
  446. err = ioutil.WriteFile(testFilePath, []byte(""), os.ModePerm)
  447. assert.NoError(t, err)
  448. f, err := os.Open(testFilePath)
  449. if assert.NoError(t, err) {
  450. err = f.Close()
  451. assert.NoError(t, err)
  452. }
  453. davFile = newWebDavFile(baseTransfer, nil, nil, nil)
  454. davFile.reader = f
  455. err = davFile.Close()
  456. assert.EqualError(t, err, common.ErrGenericFailure.Error())
  457. err = davFile.Close()
  458. assert.EqualError(t, err, common.ErrTransferClosed.Error())
  459. _, err = davFile.Read(p)
  460. assert.Error(t, err)
  461. info, err := davFile.Stat()
  462. if assert.NoError(t, err) {
  463. assert.Equal(t, int64(0), info.Size())
  464. }
  465. baseTransfer = common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFile,
  466. common.TransferDownload, 0, 0, 0, false, fs)
  467. davFile = newWebDavFile(baseTransfer, nil, nil, nil)
  468. davFile.writer = f
  469. err = davFile.Close()
  470. assert.EqualError(t, err, common.ErrGenericFailure.Error())
  471. err = os.Remove(testFilePath)
  472. assert.NoError(t, err)
  473. }
  474. func TestTransferSeek(t *testing.T) {
  475. user := dataprovider.User{
  476. HomeDir: filepath.Clean(os.TempDir()),
  477. }
  478. user.Permissions = make(map[string][]string)
  479. user.Permissions["/"] = []string{dataprovider.PermAny}
  480. fs := vfs.NewOsFs("connID", user.HomeDir, nil)
  481. connection := &Connection{
  482. BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolWebDAV, user, fs),
  483. }
  484. testFilePath := filepath.Join(user.HomeDir, testFile)
  485. baseTransfer := common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFile,
  486. common.TransferUpload, 0, 0, 0, false, fs)
  487. davFile := newWebDavFile(baseTransfer, nil, nil, nil)
  488. _, err := davFile.Seek(0, io.SeekStart)
  489. assert.EqualError(t, err, common.ErrOpUnsupported.Error())
  490. err = davFile.Close()
  491. assert.NoError(t, err)
  492. baseTransfer = common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFile,
  493. common.TransferDownload, 0, 0, 0, false, fs)
  494. davFile = newWebDavFile(baseTransfer, nil, nil, nil)
  495. _, err = davFile.Seek(0, io.SeekCurrent)
  496. assert.True(t, os.IsNotExist(err))
  497. davFile.Connection.RemoveTransfer(davFile.BaseTransfer)
  498. err = ioutil.WriteFile(testFilePath, []byte("content"), os.ModePerm)
  499. assert.NoError(t, err)
  500. f, err := os.Open(testFilePath)
  501. if assert.NoError(t, err) {
  502. err = f.Close()
  503. assert.NoError(t, err)
  504. }
  505. baseTransfer = common.NewBaseTransfer(f, connection.BaseConnection, nil, testFilePath, testFile,
  506. common.TransferDownload, 0, 0, 0, false, fs)
  507. davFile = newWebDavFile(baseTransfer, nil, nil, nil)
  508. _, err = davFile.Seek(0, io.SeekStart)
  509. assert.Error(t, err)
  510. davFile.Connection.RemoveTransfer(davFile.BaseTransfer)
  511. baseTransfer = common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFile,
  512. common.TransferDownload, 0, 0, 0, false, fs)
  513. davFile = newWebDavFile(baseTransfer, nil, nil, nil)
  514. davFile.reader = f
  515. res, err := davFile.Seek(0, io.SeekStart)
  516. assert.NoError(t, err)
  517. assert.Equal(t, int64(0), res)
  518. davFile.Connection.RemoveTransfer(davFile.BaseTransfer)
  519. info, err := os.Stat(testFilePath)
  520. assert.NoError(t, err)
  521. davFile = newWebDavFile(baseTransfer, nil, nil, info)
  522. davFile.reader = f
  523. res, err = davFile.Seek(0, io.SeekEnd)
  524. assert.NoError(t, err)
  525. assert.Equal(t, int64(7), res)
  526. davFile = newWebDavFile(baseTransfer, nil, nil, info)
  527. davFile.reader = f
  528. davFile.Fs = newMockOsFs(nil, true, fs.ConnectionID(), user.GetHomeDir())
  529. res, err = davFile.Seek(2, io.SeekStart)
  530. assert.NoError(t, err)
  531. assert.Equal(t, int64(2), res)
  532. davFile = newWebDavFile(baseTransfer, nil, nil, info)
  533. davFile.Fs = newMockOsFs(nil, true, fs.ConnectionID(), user.GetHomeDir())
  534. res, err = davFile.Seek(2, io.SeekEnd)
  535. assert.NoError(t, err)
  536. assert.Equal(t, int64(5), res)
  537. davFile = newWebDavFile(baseTransfer, nil, nil, nil)
  538. res, err = davFile.Seek(2, io.SeekEnd)
  539. assert.EqualError(t, err, "unable to get file size, seek from end not possible")
  540. assert.Equal(t, int64(0), res)
  541. assert.Len(t, common.Connections.GetStats(), 0)
  542. err = os.Remove(testFilePath)
  543. assert.NoError(t, err)
  544. }
  545. func TestBasicUsersCache(t *testing.T) {
  546. username := "webdav_internal_test"
  547. password := "pwd"
  548. u := dataprovider.User{
  549. Username: username,
  550. Password: password,
  551. HomeDir: filepath.Join(os.TempDir(), username),
  552. Status: 1,
  553. ExpirationDate: 0,
  554. }
  555. u.Permissions = make(map[string][]string)
  556. u.Permissions["/"] = []string{dataprovider.PermAny}
  557. user, _, err := httpd.AddUser(u, http.StatusOK)
  558. assert.NoError(t, err)
  559. c := &Configuration{
  560. BindPort: 9000,
  561. Cache: Cache{
  562. Enabled: true,
  563. MaxSize: 50,
  564. ExpirationTime: 1,
  565. },
  566. }
  567. server, err := newServer(c, configDir)
  568. assert.NoError(t, err)
  569. req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user.Username), nil)
  570. assert.NoError(t, err)
  571. _, _, err = server.authenticate(req)
  572. assert.Error(t, err)
  573. now := time.Now()
  574. req.SetBasicAuth(username, password)
  575. _, isCached, err := server.authenticate(req)
  576. assert.NoError(t, err)
  577. assert.False(t, isCached)
  578. // now the user should be cached
  579. var cachedUser dataprovider.CachedUser
  580. result, ok := dataprovider.GetCachedWebDAVUser(username)
  581. if assert.True(t, ok) {
  582. cachedUser = result.(dataprovider.CachedUser)
  583. assert.False(t, cachedUser.IsExpired())
  584. assert.True(t, cachedUser.Expiration.After(now.Add(time.Duration(c.Cache.ExpirationTime)*time.Minute)))
  585. // authenticate must return the cached user now
  586. authUser, isCached, err := server.authenticate(req)
  587. assert.NoError(t, err)
  588. assert.True(t, isCached)
  589. assert.Equal(t, cachedUser.User, authUser)
  590. }
  591. // a wrong password must fail
  592. req.SetBasicAuth(username, "wrong")
  593. _, _, err = server.authenticate(req)
  594. assert.EqualError(t, err, dataprovider.ErrInvalidCredentials.Error())
  595. req.SetBasicAuth(username, password)
  596. // force cached user expiration
  597. cachedUser.Expiration = now
  598. dataprovider.CacheWebDAVUser(cachedUser, c.Cache.MaxSize)
  599. result, ok = dataprovider.GetCachedWebDAVUser(username)
  600. if assert.True(t, ok) {
  601. cachedUser = result.(dataprovider.CachedUser)
  602. assert.True(t, cachedUser.IsExpired())
  603. }
  604. // now authenticate should get the user from the data provider and update the cache
  605. _, isCached, err = server.authenticate(req)
  606. assert.NoError(t, err)
  607. assert.False(t, isCached)
  608. result, ok = dataprovider.GetCachedWebDAVUser(username)
  609. if assert.True(t, ok) {
  610. cachedUser = result.(dataprovider.CachedUser)
  611. assert.False(t, cachedUser.IsExpired())
  612. }
  613. // cache is invalidated after a user modification
  614. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  615. assert.NoError(t, err)
  616. _, ok = dataprovider.GetCachedWebDAVUser(username)
  617. assert.False(t, ok)
  618. _, isCached, err = server.authenticate(req)
  619. assert.NoError(t, err)
  620. assert.False(t, isCached)
  621. _, ok = dataprovider.GetCachedWebDAVUser(username)
  622. assert.True(t, ok)
  623. // cache is invalidated after user deletion
  624. _, err = httpd.RemoveUser(user, http.StatusOK)
  625. assert.NoError(t, err)
  626. _, ok = dataprovider.GetCachedWebDAVUser(username)
  627. assert.False(t, ok)
  628. }
  629. func TestUsersCacheSizeAndExpiration(t *testing.T) {
  630. username := "webdav_internal_test"
  631. password := "pwd"
  632. u := dataprovider.User{
  633. HomeDir: filepath.Join(os.TempDir(), username),
  634. Status: 1,
  635. ExpirationDate: 0,
  636. }
  637. u.Username = username + "1"
  638. u.Password = password + "1"
  639. u.Permissions = make(map[string][]string)
  640. u.Permissions["/"] = []string{dataprovider.PermAny}
  641. user1, _, err := httpd.AddUser(u, http.StatusOK)
  642. assert.NoError(t, err)
  643. u.Username = username + "2"
  644. u.Password = password + "2"
  645. user2, _, err := httpd.AddUser(u, http.StatusOK)
  646. assert.NoError(t, err)
  647. u.Username = username + "3"
  648. u.Password = password + "3"
  649. user3, _, err := httpd.AddUser(u, http.StatusOK)
  650. assert.NoError(t, err)
  651. u.Username = username + "4"
  652. u.Password = password + "4"
  653. user4, _, err := httpd.AddUser(u, http.StatusOK)
  654. assert.NoError(t, err)
  655. c := &Configuration{
  656. BindPort: 9000,
  657. Cache: Cache{
  658. Enabled: true,
  659. MaxSize: 3,
  660. ExpirationTime: 1,
  661. },
  662. }
  663. server, err := newServer(c, configDir)
  664. assert.NoError(t, err)
  665. req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user1.Username), nil)
  666. assert.NoError(t, err)
  667. req.SetBasicAuth(user1.Username, password+"1")
  668. _, isCached, err := server.authenticate(req)
  669. assert.NoError(t, err)
  670. assert.False(t, isCached)
  671. req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user2.Username), nil)
  672. assert.NoError(t, err)
  673. req.SetBasicAuth(user2.Username, password+"2")
  674. _, isCached, err = server.authenticate(req)
  675. assert.NoError(t, err)
  676. assert.False(t, isCached)
  677. req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user3.Username), nil)
  678. assert.NoError(t, err)
  679. req.SetBasicAuth(user3.Username, password+"3")
  680. _, isCached, err = server.authenticate(req)
  681. assert.NoError(t, err)
  682. assert.False(t, isCached)
  683. // the first 3 users are now cached
  684. _, ok := dataprovider.GetCachedWebDAVUser(user1.Username)
  685. assert.True(t, ok)
  686. _, ok = dataprovider.GetCachedWebDAVUser(user2.Username)
  687. assert.True(t, ok)
  688. _, ok = dataprovider.GetCachedWebDAVUser(user3.Username)
  689. assert.True(t, ok)
  690. req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user4.Username), nil)
  691. assert.NoError(t, err)
  692. req.SetBasicAuth(user4.Username, password+"4")
  693. _, isCached, err = server.authenticate(req)
  694. assert.NoError(t, err)
  695. assert.False(t, isCached)
  696. // user1, the first cached, should be removed now
  697. _, ok = dataprovider.GetCachedWebDAVUser(user1.Username)
  698. assert.False(t, ok)
  699. _, ok = dataprovider.GetCachedWebDAVUser(user2.Username)
  700. assert.True(t, ok)
  701. _, ok = dataprovider.GetCachedWebDAVUser(user3.Username)
  702. assert.True(t, ok)
  703. _, ok = dataprovider.GetCachedWebDAVUser(user4.Username)
  704. assert.True(t, ok)
  705. // user1 logins, user2 should be removed
  706. req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user1.Username), nil)
  707. assert.NoError(t, err)
  708. req.SetBasicAuth(user1.Username, password+"1")
  709. _, isCached, err = server.authenticate(req)
  710. assert.NoError(t, err)
  711. assert.False(t, isCached)
  712. _, ok = dataprovider.GetCachedWebDAVUser(user2.Username)
  713. assert.False(t, ok)
  714. _, ok = dataprovider.GetCachedWebDAVUser(user1.Username)
  715. assert.True(t, ok)
  716. _, ok = dataprovider.GetCachedWebDAVUser(user3.Username)
  717. assert.True(t, ok)
  718. _, ok = dataprovider.GetCachedWebDAVUser(user4.Username)
  719. assert.True(t, ok)
  720. // user2 logins, user3 should be removed
  721. req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user2.Username), nil)
  722. assert.NoError(t, err)
  723. req.SetBasicAuth(user2.Username, password+"2")
  724. _, isCached, err = server.authenticate(req)
  725. assert.NoError(t, err)
  726. assert.False(t, isCached)
  727. _, ok = dataprovider.GetCachedWebDAVUser(user3.Username)
  728. assert.False(t, ok)
  729. _, ok = dataprovider.GetCachedWebDAVUser(user1.Username)
  730. assert.True(t, ok)
  731. _, ok = dataprovider.GetCachedWebDAVUser(user2.Username)
  732. assert.True(t, ok)
  733. _, ok = dataprovider.GetCachedWebDAVUser(user4.Username)
  734. assert.True(t, ok)
  735. // user3 logins, user4 should be removed
  736. req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user3.Username), nil)
  737. assert.NoError(t, err)
  738. req.SetBasicAuth(user3.Username, password+"3")
  739. _, isCached, err = server.authenticate(req)
  740. assert.NoError(t, err)
  741. assert.False(t, isCached)
  742. _, ok = dataprovider.GetCachedWebDAVUser(user4.Username)
  743. assert.False(t, ok)
  744. _, ok = dataprovider.GetCachedWebDAVUser(user1.Username)
  745. assert.True(t, ok)
  746. _, ok = dataprovider.GetCachedWebDAVUser(user2.Username)
  747. assert.True(t, ok)
  748. _, ok = dataprovider.GetCachedWebDAVUser(user3.Username)
  749. assert.True(t, ok)
  750. // now remove user1 after an update
  751. user1, _, err = httpd.UpdateUser(user1, http.StatusOK, "")
  752. assert.NoError(t, err)
  753. _, ok = dataprovider.GetCachedWebDAVUser(user1.Username)
  754. assert.False(t, ok)
  755. req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user4.Username), nil)
  756. assert.NoError(t, err)
  757. req.SetBasicAuth(user4.Username, password+"4")
  758. _, isCached, err = server.authenticate(req)
  759. assert.NoError(t, err)
  760. assert.False(t, isCached)
  761. req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("/%v", user1.Username), nil)
  762. assert.NoError(t, err)
  763. req.SetBasicAuth(user1.Username, password+"1")
  764. _, isCached, err = server.authenticate(req)
  765. assert.NoError(t, err)
  766. assert.False(t, isCached)
  767. _, ok = dataprovider.GetCachedWebDAVUser(user2.Username)
  768. assert.False(t, ok)
  769. _, ok = dataprovider.GetCachedWebDAVUser(user1.Username)
  770. assert.True(t, ok)
  771. _, ok = dataprovider.GetCachedWebDAVUser(user3.Username)
  772. assert.True(t, ok)
  773. _, ok = dataprovider.GetCachedWebDAVUser(user4.Username)
  774. assert.True(t, ok)
  775. _, err = httpd.RemoveUser(user1, http.StatusOK)
  776. assert.NoError(t, err)
  777. _, err = httpd.RemoveUser(user2, http.StatusOK)
  778. assert.NoError(t, err)
  779. _, err = httpd.RemoveUser(user3, http.StatusOK)
  780. assert.NoError(t, err)
  781. _, err = httpd.RemoveUser(user4, http.StatusOK)
  782. assert.NoError(t, err)
  783. }