Files

130 lines
4.2 KiB
Go

package files
import (
"archive/zip"
"fmt"
"io"
"net/http"
"path/filepath"
"strings"
"time"
. "github.com/mickael-kerjean/filestash/server/pkg/core"
. "github.com/mickael-kerjean/filestash/server/pkg/kernel"
. "github.com/mickael-kerjean/filestash/server/pkg/utils"
. "github.com/mickael-kerjean/filestash/server/pkg/permissions"
)
func FileDownloader(ctx *App, res http.ResponseWriter, req *http.Request) {
var err error
if CanRead(ctx) == false {
Log.Debug("downloader::permission 'permission denied'")
SendErrorResult(res, ErrPermissionDenied)
return
}
paths := req.URL.Query()["path"]
for i := 0; i < len(paths); i++ {
if paths[i], err = PathBuilder(ctx, paths[i]); err != nil {
Log.Debug("downloader::path '%s'", err.Error())
SendErrorResult(res, err)
return
}
}
resHeader := res.Header()
resHeader.Set("Content-Type", "application/zip")
filename := "download"
if len(paths) == 1 {
filename = filepath.Base(paths[0])
}
resHeader.Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s.zip\"", filename))
start := time.Now()
var addToZipRecursive func(*App, *zip.Writer, string, string, *[]string) error
addToZipRecursive = func(c *App, zw *zip.Writer, backendPath string, zipRoot string, errList *[]string) (err error) {
if time.Since(start) > time.Duration(zip_timeout())*time.Second {
Log.Debug("downloader::timeout zip not completed due to timeout")
return ErrTimeout
}
if strings.HasSuffix(backendPath, "/") == false {
// Process File
zipPath := strings.TrimPrefix(backendPath, zipRoot)
file, err := ctx.Backend.Cat(backendPath)
if err != nil {
*errList = append(*errList, fmt.Sprintf("downloader::cat %s %s\n", zipPath, err.Error()))
if err == ErrNotReachable {
return nil
}
Log.Debug("downloader::cat backendPath['%s'] zipPath['%s'] error['%s']", backendPath, zipPath, err.Error())
return err
}
zipFile, err := zw.Create(zipPath)
if err != nil {
*errList = append(*errList, fmt.Sprintf("downloader::create %s %s\n", zipPath, err.Error()))
Log.Debug("downloader::create backendPath['%s'] zipPath['%s'] error['%s']", backendPath, zipPath, err.Error())
return err
}
if _, err = io.Copy(zipFile, file); err != nil {
*errList = append(*errList, fmt.Sprintf("downloader::copy %s %s\n", zipPath, err.Error()))
Log.Debug("downloader::copy backendPath['%s'] zipPath['%s'] error['%s']", backendPath, zipPath, err.Error())
io.Copy(zipFile, strings.NewReader(""))
return err
}
file.Close()
return nil
}
// Process Folder
entries, err := c.Backend.Ls(backendPath)
if err != nil {
*errList = append(*errList, fmt.Sprintf("downloader::ls %s\n", err.Error()))
Log.Debug("downloader::ls path['%s'] error['%s']", backendPath, err.Error())
return err
}
for i := 0; i < len(entries); i++ {
newBackendPath := backendPath + entries[i].Name()
if entries[i].IsDir() {
newBackendPath += "/"
}
if err = addToZipRecursive(ctx, zw, newBackendPath, zipRoot, errList); err != nil {
*errList = append(*errList, fmt.Sprintf("downloader::recursive %s\n", err.Error()))
Log.Debug("downloader::recursive path['%s'] error['%s']", newBackendPath, err.Error())
return err
}
}
return nil
}
zipWriter := zip.NewWriter(res)
defer zipWriter.Close()
errList := []string{}
for i := 0; i < len(paths); i++ {
zipRoot := ""
if strings.HasSuffix(paths[i], "/") {
zipRoot = strings.TrimSuffix(paths[i], filepath.Base(paths[i])+"/")
} else {
zipRoot = strings.TrimSuffix(paths[i], filepath.Base(paths[i]))
}
for _, auth := range Hooks.Get.AuthorisationMiddleware() {
if err = auth.Ls(ctx, paths[i]); err != nil {
Log.Info("downloader::ls::auth path['%s'] => '%s'", paths[i], err.Error())
SendErrorResult(res, ErrNotAuthorized)
return
}
if err = auth.Cat(ctx, paths[i]); err != nil {
Log.Info("downloader::cat::auth path['%s'] => '%s'", paths[i], err.Error())
SendErrorResult(res, ErrNotAuthorized)
return
}
}
addToZipRecursive(ctx, zipWriter, paths[i], zipRoot, &errList)
}
if len(errList) > 0 {
if errorWriter, err := zipWriter.Create("error.log"); err == nil {
for _, e := range errList {
io.Copy(errorWriter, strings.NewReader(e))
}
}
}
}