package ctrl
import (
"crypto/md5"
"encoding/base32"
. "github.com/mickael-kerjean/filestash/server/common"
"io"
"text/template"
"net/http"
"os"
"path/filepath"
"strings"
)
var ETAGS map[string]string = make(map[string]string)
func StaticHandler(_path string) func(App, http.ResponseWriter, *http.Request) {
return func(ctx App, res http.ResponseWriter, req *http.Request) {
var srcPath string
var err error
if srcPath, err = JoinPath(GetAbsolutePath(_path), req.URL.Path); err != nil {
http.NotFound(res, req)
return
}
if strings.HasPrefix(_path, "/") == true {
http.NotFound(res, req)
return
}
ServeFile(res, req, srcPath)
}
}
func IndexHandler(_path string) func(App, http.ResponseWriter, *http.Request) {
return func(ctx App, res http.ResponseWriter, req *http.Request) {
if req.URL.String() != URL_SETUP && Config.Get("auth.admin").String() == "" {
http.Redirect(res, req, URL_SETUP, http.StatusTemporaryRedirect)
return
}
srcPath := GetAbsolutePath(_path)
ServeFile(res, req, srcPath)
}
}
func AboutHandler(ctx App, res http.ResponseWriter, req *http.Request) {
page := `
{{index .App 0}} ({{index .App 1}})
{{range .Plugins}}
{{ index . 0 }} ({{ index . 1 }})
{{end}}
`
t, _ := template.New("about").Parse(page)
t.Execute(res, struct {
App []string
Plugins [][]string
}{
App: []string{"Filestash " + APP_VERSION + "." + BUILD_NUMBER, hashFile(filepath.Join(GetCurrentDir(), "/filestash"), 6)},
Plugins: func () [][]string {
pPath := filepath.Join(GetCurrentDir(), PLUGIN_PATH)
file, err := os.Open(pPath)
if err != nil {
return [][]string{
[]string{"N/A", ""},
}
}
files, err := file.Readdir(0)
if err != nil {
return [][]string{
[]string{"N/A", ""},
}
}
plugins := make([][]string, 0)
plugins = append(plugins, []string {
"config.json",
hashFile(filepath.Join(GetCurrentDir(), "/data/config/config.json"), 6),
})
for i:=0; i < len(files); i++ {
plugins = append(plugins, []string{
files[i].Name(),
hashFile(pPath + "/" + files[i].Name(), 6),
})
}
return plugins
}(),
})
}
func hashFile (path string, n int) string {
f, err := os.OpenFile(path, os.O_RDONLY, os.ModePerm)
if err != nil {
return ""
}
defer f.Close()
h := md5.New()
if _, err := io.Copy(h, f); err != nil {
return ""
}
return base32.HexEncoding.EncodeToString(h.Sum(nil))[:n]
}
func ServeFile(res http.ResponseWriter, req *http.Request, filePath string) {
zFilePath := filePath + ".gz"
if req.Header.Get("If-None-Match") != "" {
if req.Header.Get("If-None-Match") == ETAGS[filePath] {
res.WriteHeader(http.StatusNotModified)
return
} else if req.Header.Get("If-None-Match") == ETAGS[zFilePath] {
res.WriteHeader(http.StatusNotModified)
return
}
}
head := res.Header()
if strings.Contains(req.Header.Get("Accept-Encoding"), "gzip") {
if file, err := os.OpenFile(zFilePath, os.O_RDONLY, os.ModePerm); err == nil {
head.Set("Content-Encoding", "gzip")
if ETAGS[zFilePath] == "" {
ETAGS[zFilePath] = hashFile(zFilePath, 10)
}
head.Set("Etag", ETAGS[zFilePath])
io.Copy(res, file)
return
}
}
file, err := os.OpenFile(filePath, os.O_RDONLY, os.ModePerm)
if err != nil {
http.NotFound(res, req)
return
}
if ETAGS[filePath] == "" {
ETAGS[filePath] = hashFile(filePath, 10)
}
head.Set("Etag", ETAGS[filePath])
io.Copy(res, file)
}