package ctrl import ( . "github.com/mickael-kerjean/filestash/server/common" "fmt" "io" "text/template" "net/http" URL "net/url" "os" "path/filepath" "strings" ) func StaticHandler(_path string) func(App, http.ResponseWriter, *http.Request) { return func(ctx App, res http.ResponseWriter, req *http.Request) { var base string = GetAbsolutePath(_path) var srcPath string if srcPath = JoinPath(base, req.URL.Path); srcPath == base { 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) { urlObj, err := URL.Parse(req.URL.String()) if err != nil { res.WriteHeader(http.StatusInternalServerError) res.Write([]byte(Page("

404 - Not Found

"))) return } url := urlObj.Path if url != URL_SETUP && Config.Get("auth.admin").String() == "" { http.Redirect(res, req, URL_SETUP, http.StatusTemporaryRedirect) return } else if url != "/" && strings.HasPrefix(url, "/s/") == false && strings.HasPrefix(url, "/view/") == false && strings.HasPrefix(url, "/files/") == false && url != "/login" && url != "/logout" && strings.HasPrefix(url, "/admin") == false { res.WriteHeader(http.StatusNotFound) res.Write([]byte(Page("

404 - Not Found

"))) return } ua := req.Header.Get("User-Agent"); if strings.Contains(ua, "MSIE ") || strings.Contains(ua, "Edge/"){ // Microsoft is behaving on many occasion differently than Firefox / Chrome. // I have neither the time / motivation for it to work properly res.WriteHeader(http.StatusBadRequest) res.Write([]byte( Page(`

Internet explorer is not supported

We don't support IE / Edge at this time
Please use either Chromium, Firefox or Chrome

`))) return } srcPath := GetAbsolutePath(_path) ServeFile(res, req, srcPath) } } func AboutHandler(ctx App, res http.ResponseWriter, req *http.Request) { t, _ := template.New("about").Parse(Page(`

{{index .App 0}}

Commit hash {{ index .App 1}}
Binary hash {{ index .App 2}}
Config hash {{ index .App 3}}
`)) t.Execute(res, struct { App []string }{ []string{ "Filestash " + APP_VERSION + "." + BUILD_DATE, BUILD_REF, hashFileContent(filepath.Join(GetCurrentDir(), "/filestash"), 0), hashFileContent(filepath.Join(GetCurrentDir(), CONFIG_PATH, "config.json"), 0), }}) } func ServeFile(res http.ResponseWriter, req *http.Request, filePath string) { zFilePath := filePath + ".gz" bFilePath := filePath + ".br" etagNormal := hashFile(filePath, 10) etagGzip := hashFile(zFilePath, 10) etagBr := hashFile(bFilePath, 10) if req.Header.Get("If-None-Match") != "" { browserTag := req.Header.Get("If-None-Match") if browserTag == etagNormal { res.WriteHeader(http.StatusNotModified) return } else if browserTag == etagBr { res.WriteHeader(http.StatusNotModified) return } else if browserTag == etagGzip { res.WriteHeader(http.StatusNotModified) return } } head := res.Header() acceptEncoding := req.Header.Get("Accept-Encoding") if strings.Contains(acceptEncoding, "br") { if file, err := os.OpenFile(bFilePath, os.O_RDONLY, os.ModePerm); err == nil { head.Set("Content-Encoding", "br") head.Set("Etag", etagBr) io.Copy(res, file) file.Close() return } } else if strings.Contains(acceptEncoding, "gzip") { if file, err := os.OpenFile(zFilePath, os.O_RDONLY, os.ModePerm); err == nil { head.Set("Content-Encoding", "gzip") head.Set("Etag", etagGzip) io.Copy(res, file) file.Close() return } } file, err := os.OpenFile(filePath, os.O_RDONLY, os.ModePerm) if err != nil { http.NotFound(res, req) return } head.Set("Etag", etagNormal) io.Copy(res, file) file.Close() } func hashFile(path string, n int) string { f, err := os.OpenFile(path, os.O_RDONLY, os.ModePerm) if err != nil { return "" } defer f.Close() stat, err := f.Stat() if err != nil { return "" } return QuickHash(fmt.Sprintf("%s %d %d %s", path, stat.Size(), stat.Mode(), stat.ModTime()), n) } func hashFileContent(path string, n int) string { f, err := os.OpenFile(path, os.O_RDONLY, os.ModePerm) if err != nil { return "" } defer f.Close() return HashStream(f, n) }