filebrowser/http/raw.go
Henrique Dias 42227d9edd feat: many updates (see PR)
feat: add main command

feat: add todos

feat: add signup api

feat: do not repeat code

fix: user return

feat: work out static box

fix: setup static handlers

feat: add share types

License: MIT
Signed-off-by: Henrique Dias <hacdias@gmail.com>

feat: start static

License: MIT
Signed-off-by: Henrique Dias <hacdias@gmail.com>

feat: bring back more features

License: MIT
Signed-off-by: Henrique Dias <hacdias@gmail.com>

add

feat: readd more files

License: MIT
Signed-off-by: Henrique Dias <hacdias@gmail.com>

feat: add dockerignore

License: MIT
Signed-off-by: Henrique Dias <hacdias@gmail.com>

feat: gitignore

License: MIT
Signed-off-by: Henrique Dias <hacdias@gmail.com>

feat: readd submodule

License: MIT
Signed-off-by: Henrique Dias <hacdias@gmail.com>
2018-12-28 23:40:11 +00:00

164 lines
3.5 KiB
Go

package http
import (
"errors"
"net/http"
"net/url"
"path/filepath"
"strings"
"github.com/filebrowser/filebrowser/types"
"github.com/hacdias/fileutils"
"github.com/mholt/archiver"
)
const apiRawPrefix = "/api/raw"
func parseQueryFiles(r *http.Request, f *types.File, u *types.User) ([]string, error) {
files := []string{}
names := strings.Split(r.URL.Query().Get("files"), ",")
if len(names) == 0 {
files = append(files, f.Path)
} else {
for _, name := range names {
name, err := url.QueryUnescape(name)
if err != nil {
return nil, err
}
name = fileutils.SlashClean(name)
if !u.IsAllowed(name) {
continue
}
files = append(files, filepath.Join(f.Path, name))
}
}
return files, nil
}
func parseQueryAlgorithm(r *http.Request) (string, archiver.Writer, error) {
switch r.URL.Query().Get("algo") {
case "zip", "true", "":
return ".zip", archiver.NewZip(), nil
case "tar":
return ".tar", archiver.NewTar(), nil
case "targz":
return ".tar.gz", archiver.NewTarGz(), nil
case "tarbz2":
return ".tar.bz2", archiver.NewTarBz2(), nil
case "tarxz":
return ".tar.xz", archiver.NewTarXz(), nil
case "tarlz4":
return ".tar.lz4", archiver.NewTarLz4(), nil
case "tarsz":
return ".tar.sz", archiver.NewTarSz(), nil
default:
return "", nil, errors.New("format not implemented")
}
}
func (e *Env) rawHandler(w http.ResponseWriter, r *http.Request) {
path, user, ok := e.getResourceData(w, r, apiRawPrefix)
if !ok {
return
}
if !user.Perm.Download {
httpErr(w, http.StatusForbidden, nil)
return
}
file, err := types.NewFileInfo(user, path)
if err != nil {
httpErr(w, httpFsErr(err), err)
return
}
if !file.IsDir {
fileHandler(w, r, file, user)
return
}
filenames, err := parseQueryFiles(r, file, user)
if err != nil {
httpErr(w, http.StatusInternalServerError, err)
return
}
extension, ar, err := parseQueryAlgorithm(r)
if err != nil {
httpErr(w, http.StatusInternalServerError, err)
return
}
name := file.Name
if name == "." || name == "" {
name = "archive"
}
name += extension
w.Header().Set("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(name))
err = ar.Create(w)
if err != nil {
httpErr(w, http.StatusInternalServerError, err)
return
}
defer ar.Close()
for _, fname := range filenames {
info, err := user.Fs.Stat(fname)
if err != nil {
httpErr(w, http.StatusInternalServerError, err)
return
}
// get file's name for the inside of the archive
internalName, err := archiver.NameInArchive(info, fname, fname)
if err != nil {
httpErr(w, http.StatusInternalServerError, err)
return
}
// open the file
file, err := user.Fs.Open(fname)
if err != nil {
httpErr(w, http.StatusInternalServerError, err)
return
}
// write it to the archive
err = ar.Write(archiver.File{
FileInfo: archiver.FileInfo{
FileInfo: info,
CustomName: internalName,
},
ReadCloser: file,
})
file.Close()
if err != nil {
httpErr(w, http.StatusInternalServerError, err)
return
}
}
}
func fileHandler(w http.ResponseWriter, r *http.Request, file *types.File, user *types.User) {
fd, err := user.Fs.Open(file.Path)
if err != nil {
httpErr(w, http.StatusInternalServerError, err)
return
}
defer fd.Close()
if r.URL.Query().Get("inline") == "true" {
w.Header().Set("Content-Disposition", "inline")
} else {
// As per RFC6266 section 4.3
w.Header().Set("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(file.Name))
}
http.ServeContent(w, r, file.Name, file.ModTime, fd)
}