diff --git a/cmd/files.go b/cmd/files.go index cf77891..5d02612 100644 --- a/cmd/files.go +++ b/cmd/files.go @@ -30,10 +30,9 @@ func appendPaths(m map[string][]string, path, filter string) (map[string][]strin directory, _ := filepath.Split(absolutePath) - switch { - case filter != "" && strings.Contains(path, filter): + if filter != "" && strings.Contains(path, filter) { m[directory] = append(m[directory], path) - case filter == "": + } else if filter == "" { m[directory] = append(m[directory], path) } @@ -55,7 +54,7 @@ func getFirstFile(path string) (string, error) { fileName := fmt.Sprintf("%v%.3d%v", base, number, extension) - nextFile, err := checkNextFile(fileName) + nextFile, err := nextFileExists(fileName) if err != nil { return "", err } @@ -87,7 +86,7 @@ func getNextFile(path string) (string, error) { fileName := fmt.Sprintf("%v%.3d%v", base, incremented, extension) - nextFile, err := checkNextFile(fileName) + nextFile, err := nextFileExists(fileName) if err != nil { return "", err } @@ -99,7 +98,40 @@ func getNextFile(path string) (string, error) { return fileName, nil } -func checkNextFile(path string) (bool, error) { +func pathIsValid(filePath string, paths []string) bool { + var matchesPrefix = false + for i := 0; i < len(paths); i++ { + if strings.HasPrefix(filePath, paths[i]) { + matchesPrefix = true + } + } + if !matchesPrefix { + if Verbose { + fmt.Printf("%v Failed to serve file outside specified path(s): %v\n", time.Now().Format(LOGDATE), filePath) + } + + return false + } + + return true +} + +func fileExists(filePath string) (bool, error) { + _, err := os.Stat(filePath) + if errors.Is(err, os.ErrNotExist) { + if Verbose { + fmt.Printf("%v Failed to serve non-existent file: %v\n", time.Now().Format(LOGDATE), filePath) + } + + return false, nil + } else if !errors.Is(err, os.ErrNotExist) && err != nil { + return false, err + } + + return true, nil +} + +func nextFileExists(path string) (bool, error) { _, err := os.Stat(path) switch { case err == nil: @@ -111,7 +143,7 @@ func checkNextFile(path string) (bool, error) { } } -func checkIfImage(path string) (bool, error) { +func isImage(path string) (bool, error) { file, err := os.Open(path) if err != nil { return false, err @@ -121,11 +153,7 @@ func checkIfImage(path string) (bool, error) { head := make([]byte, 261) file.Read(head) - if filetype.IsImage(head) { - return true, nil - } - - return false, nil + return filetype.IsImage(head), nil } func getFiles(m map[string][]string, path, filter string) (map[string][]string, error) { @@ -173,9 +201,7 @@ func getFileList(paths []string, filter string) (map[string][]string, error) { } func cleanFilename(filename string) string { - filename = filename[:len(filename)-(len(filepath.Ext(filename))+3)] - - return filename + return filename[:len(filename)-(len(filepath.Ext(filename))+3)] } func prepareDirectory(directory []string) []string { @@ -189,10 +215,8 @@ func prepareDirectory(directory []string) []string { if first == last { d := append([]string{}, directory[0]) - fmt.Printf("Appending %v to empty directory\n", d) return d } else { - fmt.Printf("Returning directory as-is\n") return directory } } @@ -208,12 +232,11 @@ func prepareDirectories(m map[string][]string, successive string) []string { i++ } - switch { - case successive != "": + if successive != "" { for i := 0; i < len(keys); i++ { directories = append(directories, prepareDirectory(m[keys[i]])...) } - default: + } else { for i := 0; i < len(keys); i++ { directories = append(directories, m[keys[i]]...) } @@ -228,15 +251,15 @@ func pickFile(args []string, filter, successive string) (string, error) { return "", err } - rand.Seed(time.Now().UnixNano()) - fileList := prepareDirectories(fileMap, successive) + rand.Seed(time.Now().UnixNano()) + rand.Shuffle(len(fileList), func(i, j int) { fileList[i], fileList[j] = fileList[j], fileList[i] }) for i := 0; i < len(fileList); i++ { filePath := fileList[i] - isImage, err := checkIfImage(filePath) + isImage, err := isImage(filePath) if err != nil { return "", err } diff --git a/cmd/version.go b/cmd/version.go index f1efa95..0af7398 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -10,7 +10,7 @@ import ( "github.com/spf13/cobra" ) -var Version = "0.12.3" +var Version = "0.12.4" func init() { rootCmd.AddCommand(versionCmd) diff --git a/cmd/web.go b/cmd/web.go index c1368ab..096ceae 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -5,10 +5,8 @@ Copyright © 2022 Seednode package cmd import ( - "errors" "fmt" "io" - "log" "net/http" "net/url" "os" @@ -18,17 +16,26 @@ import ( "time" ) -const LOGDATE string = "2006-01-02T15:04:05.000000000-07:00" +type appHandler func(http.ResponseWriter, *http.Request) error +func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if err := fn(w, r); err != nil { + http.Error(w, err.Error(), 500) + } +} + +const LOGDATE string = "2006-01-02T15:04:05.000000000-07:00" const PREFIX string = "/src" -func stripQueryParam(inUrl string) string { - u, err := url.Parse(inUrl) +func stripQueryParam(inUrl string) (string, error) { + url, err := url.Parse(inUrl) if err != nil { - panic(err) + return "", err } - u.RawQuery = "" - return u.String() + + url.RawQuery = "" + + return url.String(), nil } func refererToUri(referer string) string { @@ -69,42 +76,31 @@ func serveHtml(w http.ResponseWriter, r http.Request, filePath string) error { } func serveStaticFile(w http.ResponseWriter, r http.Request, paths []string) error { - prefixedFilePath, err := url.QueryUnescape(stripQueryParam(r.URL.Path)) + strippedUrl, err := stripQueryParam(r.URL.Path) + if err != nil { + return err + } + + prefixedFilePath, err := url.QueryUnescape(strippedUrl) if err != nil { return err } filePath := strings.TrimPrefix(prefixedFilePath, PREFIX) - var matchesPrefix = false - for i := 0; i < len(paths); i++ { - if strings.HasPrefix(filePath, paths[i]) { - matchesPrefix = true - } - } - if !matchesPrefix { - if Verbose { - fmt.Printf("%v Failed to serve file outside specified path(s): %v\n", time.Now().Format(LOGDATE), filePath) - } - + if !pathIsValid(filePath, paths) { http.NotFound(w, &r) - - return nil } - _, err = os.Stat(filePath) - if errors.Is(err, os.ErrNotExist) { - if Verbose { - fmt.Printf("%v Failed to serve non-existent file: %v\n", time.Now().Format(LOGDATE), filePath) - } - - http.NotFound(w, &r) - - return nil - } else if !errors.Is(err, os.ErrNotExist) && err != nil { + exists, err := fileExists(filePath) + if err != nil { return err } + if !exists { + http.NotFound(w, &r) + } + var startTime time.Time if Verbose { startTime = time.Now() @@ -125,18 +121,23 @@ func serveStaticFile(w http.ResponseWriter, r http.Request, paths []string) erro return nil } -func serveStaticFileHandler(paths []string) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func serveStaticFileHandler(paths []string) appHandler { + return func(w http.ResponseWriter, r *http.Request) error { err := serveStaticFile(w, *r, paths) if err != nil { - log.Fatal(err) + return err } + + return nil } } -func serveHtmlHandler(paths []string) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - refererUri := stripQueryParam(refererToUri(r.Referer())) +func serveHtmlHandler(paths []string) appHandler { + return func(w http.ResponseWriter, r *http.Request) error { + refererUri, err := stripQueryParam(refererToUri(r.Referer())) + if err != nil { + return err + } filter := r.URL.Query().Get("f") successive := r.URL.Query().Get("s") @@ -145,12 +146,12 @@ func serveHtmlHandler(paths []string) http.HandlerFunc { case r.URL.Path == "/" && successive == "true" && refererUri != "": query, err := url.QueryUnescape(refererUri) if err != nil { - log.Fatal(err) + return err } filePath, err := getNextFile(query) if err != nil { - log.Fatal(err) + return err } if filePath == "" { @@ -158,14 +159,14 @@ func serveHtmlHandler(paths []string) http.HandlerFunc { switch { case err != nil && err == ErrNoImagesFound: http.NotFound(w, r) - return + return nil case err != nil: - log.Fatal(err) + return err } filePath, err = getFirstFile(filePath) if err != nil { - log.Fatal(err) + return err } } @@ -173,29 +174,27 @@ func serveHtmlHandler(paths []string) http.HandlerFunc { http.Redirect(w, r, newUrl, http.StatusSeeOther) case r.URL.Path == "/" && successive == "true" && refererUri == "": filePath, err := pickFile(paths, filter, successive) - switch { - case err != nil && err == ErrNoImagesFound: + if err != nil && err == ErrNoImagesFound { http.NotFound(w, r) - return - case err != nil: - log.Fatal(err) + return nil + } else if err != nil { + return err } filePath, err = getFirstFile(filePath) if err != nil { - log.Fatal(err) + return err } newUrl := fmt.Sprintf("%v%v?f=%v&s=%v", r.URL.Host, filePath, filter, successive) http.Redirect(w, r, newUrl, http.StatusSeeOther) case r.URL.Path == "/": filePath, err := pickFile(paths, filter, successive) - switch { - case err != nil && err == ErrNoImagesFound: + if err != nil && err == ErrNoImagesFound { http.NotFound(w, r) - return - case err != nil: - log.Fatal(err) + return nil + } else if err != nil { + return err } newUrl := fmt.Sprintf("%v%v?f=%v&s=%v", r.URL.Host, filePath, filter, successive) @@ -203,42 +202,44 @@ func serveHtmlHandler(paths []string) http.HandlerFunc { default: filePath := r.URL.Path - isImage, err := checkIfImage(filePath) + image, err := isImage(filePath) if err != nil { - log.Fatal(err) + return err } - if !isImage { + if !image { http.NotFound(w, r) } err = serveHtml(w, *r, filePath) if err != nil { - log.Fatal(err) + return err } } + + return nil } } func doNothing(http.ResponseWriter, *http.Request) {} -func ServePage(args []string) { +func ServePage(args []string) error { paths, err := normalizePaths(args) if err != nil { - log.Fatal(err) + return err } for _, i := range paths { fmt.Println("Paths: " + i) } - http.HandleFunc("/", serveHtmlHandler(paths)) + http.Handle("/", serveHtmlHandler(paths)) http.Handle(PREFIX+"/", http.StripPrefix(PREFIX, serveStaticFileHandler(paths))) http.HandleFunc("/favicon.ico", doNothing) - port := strconv.Itoa(Port) - - err = http.ListenAndServe(":"+port, nil) + err = http.ListenAndServe(":"+strconv.Itoa(Port), nil) if err != nil { - log.Fatal(err) + return err } + + return nil }