internal_test.go 30 KB

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