From 5167ff457eaf64d3e8eb0002a68c4f83fa34f1aa Mon Sep 17 00:00:00 2001 From: Seednode Date: Fri, 5 Jan 2024 18:50:45 -0600 Subject: [PATCH] Allow empty paths, notifying if no valid files are found --- cmd/errors.go | 37 ++++++++++++------------------------- cmd/files.go | 20 ++++++++++++++++++-- cmd/root.go | 4 +++- cmd/web.go | 33 ++++++++++++++++++++++++++++----- 4 files changed, 61 insertions(+), 33 deletions(-) diff --git a/cmd/errors.go b/cmd/errors.go index 0e240bf..4bf4477 100644 --- a/cmd/errors.go +++ b/cmd/errors.go @@ -9,7 +9,6 @@ import ( "fmt" "io" "net/http" - "strings" "time" "github.com/yosssi/gohtml" @@ -25,21 +24,17 @@ var ( ErrNoMediaFound = errors.New("no supported media formats found which match all criteria") ) -func newErrorPage(title, body string) string { - var htmlBody strings.Builder - - htmlBody.WriteString(``) - htmlBody.WriteString(faviconHtml) - htmlBody.WriteString(``) - htmlBody.WriteString(fmt.Sprintf("%s", title)) - htmlBody.WriteString(fmt.Sprintf("%s", body)) - - return htmlBody.String() -} - func notFound(w http.ResponseWriter, r *http.Request, path string) error { startTime := time.Now() + w.WriteHeader(http.StatusNotFound) + w.Header().Add("Content-Type", "text/html") + + _, err := io.WriteString(w, gohtml.Format(newPage("Not Found", "404 Page not found"))) + if err != nil { + return err + } + if Verbose { fmt.Printf("%s | ERROR: Unavailable file %s requested by %s\n", startTime.Format(logDate), @@ -48,20 +43,16 @@ func notFound(w http.ResponseWriter, r *http.Request, path string) error { ) } - w.WriteHeader(http.StatusNotFound) - w.Header().Add("Content-Type", "text/html") - - _, err := io.WriteString(w, gohtml.Format(newErrorPage("Not Found", "404 Page not found"))) - if err != nil { - return err - } - return nil } func serverError(w http.ResponseWriter, r *http.Request, i interface{}) { startTime := time.Now() + w.Header().Add("Content-Type", "text/html") + + io.WriteString(w, gohtml.Format(newPage("Server Error", "An error has occurred. Please try again."))) + if Verbose { fmt.Printf("%s | ERROR: Invalid request for %s from %s\n", startTime.Format(logDate), @@ -69,10 +60,6 @@ func serverError(w http.ResponseWriter, r *http.Request, i interface{}) { r.RemoteAddr, ) } - - w.Header().Add("Content-Type", "text/html") - - io.WriteString(w, gohtml.Format(newErrorPage("Server Error", "An error has occurred. Please try again."))) } func serverErrorHandler() func(http.ResponseWriter, *http.Request, interface{}) { diff --git a/cmd/files.go b/cmd/files.go index 1052ae2..92e685a 100644 --- a/cmd/files.go +++ b/cmd/files.go @@ -10,6 +10,7 @@ import ( "io/fs" "math/big" "regexp" + "runtime" "slices" "crypto/rand" @@ -205,6 +206,10 @@ func pathIsValid(path string, paths []string) bool { } func hasSupportedFiles(path string, formats types.Types) (bool, error) { + if AllowEmpty { + return true, nil + } + hasRegisteredFiles := make(chan bool, 1) err := filepath.WalkDir(path, func(p string, info os.DirEntry, err error) error { @@ -463,7 +468,7 @@ Poll: filesMatched+filesSkipped, directoriesMatched, directoriesMatched+directoriesSkipped, - time.Since(startTime), + time.Since(startTime)-100*time.Millisecond, ) } @@ -514,7 +519,10 @@ func fileList(paths []string, filters *filters, sort string, index *fileIndex, f func pickFile(list []string) (string, error) { fileCount := len(list) - if fileCount < 1 { + switch { + case fileCount < 1 && AllowEmpty: + return "", nil + case fileCount < 1: return "", ErrNoMediaFound } @@ -531,6 +539,14 @@ func pickFile(list []string) (string, error) { return list[val], nil } +func preparePath(prefix, path string) string { + if runtime.GOOS == "windows" { + return fmt.Sprintf("%s/%s", prefix, filepath.ToSlash(path)) + } + + return prefix + path +} + func normalizePath(path string) (string, error) { homeDir, err := os.UserHomeDir() if err != nil { diff --git a/cmd/root.go b/cmd/root.go index 4160470..325fef6 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -14,12 +14,13 @@ import ( const ( AllowedCharacters string = `^[A-z0-9.\-_]+$` - ReleaseVersion string = "3.7.2" + ReleaseVersion string = "3.8.0" ) var ( AdminPrefix string All bool + AllowEmpty bool Audio bool BinaryPrefix bool Bind string @@ -111,6 +112,7 @@ func Execute() { func init() { rootCmd.Flags().StringVar(&AdminPrefix, "admin-prefix", "", "string to prepend to administrative paths") rootCmd.Flags().BoolVarP(&All, "all", "a", false, "enable all supported file types") + rootCmd.Flags().BoolVar(&AllowEmpty, "allow-empty", false, "allow specifying paths containing no supported files") rootCmd.Flags().BoolVar(&Audio, "audio", false, "enable support for audio files") rootCmd.Flags().BoolVar(&BinaryPrefix, "binary-prefix", false, "use IEC binary prefixes instead of SI decimal prefixes") rootCmd.Flags().StringVarP(&Bind, "bind", "b", "0.0.0.0", "address to bind to") diff --git a/cmd/web.go b/cmd/web.go index a8b9e28..78503e8 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -42,12 +42,31 @@ const ( timeout time.Duration = 10 * time.Second ) -func preparePath(prefix, path string) string { - if runtime.GOOS == "windows" { - return fmt.Sprintf("%s/%s", prefix, filepath.ToSlash(path)) - } +func newPage(title, body string) string { + var htmlBody strings.Builder - return prefix + path + htmlBody.WriteString(``) + htmlBody.WriteString(faviconHtml) + htmlBody.WriteString(``) + htmlBody.WriteString(fmt.Sprintf("%s", title)) + htmlBody.WriteString(fmt.Sprintf("%s", body)) + + return htmlBody.String() +} + +func noFiles(w http.ResponseWriter, r *http.Request) { + startTime := time.Now() + + w.Header().Set("Content-Type", "text/plain") + + w.Write([]byte("No files found in the specified path(s).\n")) + + if Verbose { + fmt.Printf("%s | SERVE: Empty path notice served to %s\n", + startTime.Format(logDate), + r.RemoteAddr, + ) + } } func serveStaticFile(paths []string, index *fileIndex, errorChannel chan<- error) httprouter.Handle { @@ -210,6 +229,10 @@ func serveRoot(paths []string, regexes *regexes, index *fileIndex, formats types path, err = newFile(list, sortOrder, regexes, formats) switch { + case path == "": + noFiles(w, r) + + return case err != nil && err == ErrNoMediaFound: notFound(w, r, path)