From fdd33376ce4ba5224ebedd2c2cbe21ffe77394ea Mon Sep 17 00:00:00 2001 From: Seednode Date: Wed, 13 Sep 2023 23:24:29 -0500 Subject: [PATCH] Add --prefix flag for easy reverse proxying --- README.md | 2 ++ cmd/cache.go | 2 +- cmd/info.go | 18 ++++++------ cmd/profile.go | 10 +++---- cmd/root.go | 6 +++- cmd/web.go | 62 ++++++++++++++++++++++++++++++------------ types/audio/audio.go | 8 +++--- types/flash/flash.go | 6 ++-- types/images/images.go | 8 +++--- types/text/text.go | 8 +++--- types/types.go | 4 +-- types/video/video.go | 8 +++--- 12 files changed, 88 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index bd8941f..aff3b2a 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,7 @@ Flags: --cache-file string path to optional persistent cache file -f, --filter enable filtering --flash enable support for shockwave flash files (via ruffle.rs) + --handlers display registered handlers (for debugging) -h, --help help for roulette --images enable support for image files -i, --info expose informational endpoints @@ -121,6 +122,7 @@ Flags: --minimum-files uint32 skip directories with file counts below this value (default 1) --page-length uint32 pagination length for statistics and debug pages -p, --port uint16 port to listen on (default 8080) + --prefix string path with which to prefix all listeners (for reverse proxying) --profile register net/http/pprof handlers -r, --recursive recurse into subdirectories --refresh-interval string force refresh interval equal to this duration (minimum 500ms) diff --git a/cmd/cache.go b/cmd/cache.go index 813b846..8cf4ab0 100644 --- a/cmd/cache.go +++ b/cmd/cache.go @@ -152,5 +152,5 @@ func registerCacheHandlers(mux *httprouter.Router, args []string, cache *fileCac cache.generate(args, formats) } - mux.GET("/clear_cache", serveCacheClear(args, cache, formats)) + register(mux, Prefix+"/clear_cache", serveCacheClear(args, cache, formats)) } diff --git a/cmd/info.go b/cmd/info.go index 1182dd6..fa520fc 100644 --- a/cmd/info.go +++ b/cmd/info.go @@ -65,7 +65,7 @@ func serveIndexHtml(args []string, cache *fileCache, paginate bool) httprouter.H if Sorting { shouldSort = "?sort=asc" } - htmlBody.WriteString(fmt.Sprintf("%s\n", mediaPrefix, v, shouldSort, v)) + htmlBody.WriteString(fmt.Sprintf("%s\n", Prefix, mediaPrefix, v, shouldSort, v)) } } if PageLength != 0 { @@ -274,19 +274,19 @@ func serveEnabledMimeTypes(formats *types.Types) httprouter.Handle { func registerInfoHandlers(mux *httprouter.Router, args []string, cache *fileCache, formats *types.Types) { if Cache { - mux.GET("/html/", serveIndexHtml(args, cache, false)) + register(mux, Prefix+"/html/", serveIndexHtml(args, cache, false)) if PageLength != 0 { - mux.GET("/html/:page", serveIndexHtml(args, cache, true)) + register(mux, Prefix+"/html/:page", serveIndexHtml(args, cache, true)) } - mux.GET("/json", serveIndexJson(args, cache)) + register(mux, Prefix+"/json", serveIndexJson(args, cache)) if PageLength != 0 { - mux.GET("/json/:page", serveIndexJson(args, cache)) + register(mux, Prefix+"/json/:page", serveIndexJson(args, cache)) } } - mux.GET("/available_extensions", serveAvailableExtensions()) - mux.GET("/enabled_extensions", serveEnabledExtensions(formats)) - mux.GET("/available_mime_types", serveAvailableMimeTypes()) - mux.GET("/enabled_mime_types", serveEnabledMimeTypes(formats)) + register(mux, Prefix+"/available_extensions", serveAvailableExtensions()) + register(mux, Prefix+"/enabled_extensions", serveEnabledExtensions(formats)) + register(mux, Prefix+"/available_mime_types", serveAvailableMimeTypes()) + register(mux, Prefix+"/enabled_mime_types", serveEnabledMimeTypes(formats)) } diff --git a/cmd/profile.go b/cmd/profile.go index a1e9907..4e3db41 100644 --- a/cmd/profile.go +++ b/cmd/profile.go @@ -11,9 +11,9 @@ import ( ) func registerProfileHandlers(mux *httprouter.Router) { - mux.HandlerFunc("GET", "/debug/pprof/", pprof.Index) - mux.HandlerFunc("GET", "/debug/pprof/cmdline", pprof.Cmdline) - mux.HandlerFunc("GET", "/debug/pprof/profile", pprof.Profile) - mux.HandlerFunc("GET", "/debug/pprof/symbol", pprof.Symbol) - mux.HandlerFunc("GET", "/debug/pprof/trace", pprof.Trace) + mux.HandlerFunc("GET", Prefix+"/debug/pprof/", pprof.Index) + mux.HandlerFunc("GET", Prefix+"/debug/pprof/cmdline", pprof.Cmdline) + mux.HandlerFunc("GET", Prefix+"/debug/pprof/profile", pprof.Profile) + mux.HandlerFunc("GET", Prefix+"/debug/pprof/symbol", pprof.Symbol) + mux.HandlerFunc("GET", Prefix+"/debug/pprof/trace", pprof.Trace) } diff --git a/cmd/root.go b/cmd/root.go index 293ce25..96dae4a 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -12,7 +12,7 @@ import ( ) const ( - ReleaseVersion string = "0.80.1" + ReleaseVersion string = "0.81.0" ) var ( @@ -23,12 +23,14 @@ var ( CacheFile string Filtering bool Flash bool + Handlers bool Images bool Info bool MaximumFileCount uint32 MinimumFileCount uint32 PageLength uint32 Port uint16 + Prefix string Profile bool Recursive bool RefreshInterval string @@ -79,12 +81,14 @@ func init() { rootCmd.Flags().StringVar(&CacheFile, "cache-file", "", "path to optional persistent cache file") rootCmd.Flags().BoolVarP(&Filtering, "filter", "f", false, "enable filtering") rootCmd.Flags().BoolVar(&Flash, "flash", false, "enable support for shockwave flash files (via ruffle.rs)") + rootCmd.Flags().BoolVar(&Handlers, "handlers", false, "display registered handlers (for debugging)") rootCmd.Flags().BoolVar(&Images, "images", false, "enable support for image files") rootCmd.Flags().BoolVarP(&Info, "info", "i", false, "expose informational endpoints") rootCmd.Flags().Uint32Var(&MaximumFileCount, "maximum-files", 1<<32-1, "skip directories with file counts above this value") rootCmd.Flags().Uint32Var(&MinimumFileCount, "minimum-files", 1, "skip directories with file counts below this value") rootCmd.Flags().Uint32Var(&PageLength, "page-length", 0, "pagination length for statistics and debug pages") rootCmd.Flags().Uint16VarP(&Port, "port", "p", 8080, "port to listen on") + rootCmd.Flags().StringVar(&Prefix, "prefix", "", "path with which to prefix all listeners (for reverse proxying)") rootCmd.Flags().BoolVar(&Profile, "profile", false, "register net/http/pprof handlers") rootCmd.Flags().BoolVarP(&Recursive, "recursive", "r", false, "recurse into subdirectories") rootCmd.Flags().StringVar(&RefreshInterval, "refresh-interval", "", "force refresh interval equal to this duration (minimum 500ms)") diff --git a/cmd/web.go b/cmd/web.go index 76f4197..26f2741 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -40,7 +40,9 @@ const ( func serveStaticFile(paths []string, cache *fileCache) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { - path := strings.TrimPrefix(r.URL.Path, sourcePrefix) + prefix := Prefix + sourcePrefix + + path := strings.TrimPrefix(r.URL.Path, prefix) prefixedFilePath, err := stripQueryParams(path) if err != nil { @@ -51,7 +53,7 @@ func serveStaticFile(paths []string, cache *fileCache) httprouter.Handle { return } - filePath, err := filepath.EvalSymlinks(strings.TrimPrefix(prefixedFilePath, sourcePrefix)) + filePath, err := filepath.EvalSymlinks(strings.TrimPrefix(prefixedFilePath, prefix)) if err != nil { fmt.Println(err) @@ -134,7 +136,7 @@ func serveRoot(paths []string, regexes *regexes, cache *fileCache, formats *type return } - strippedRefererUri := strings.TrimPrefix(refererUri, mediaPrefix) + strippedRefererUri := strings.TrimPrefix(refererUri, Prefix+mediaPrefix) filters := &filters{ included: splitQueryParams(r.URL.Query().Get("include"), regexes), @@ -187,8 +189,9 @@ func serveRoot(paths []string, regexes *regexes, cache *fileCache, formats *type queryParams := generateQueryParams(filters, sortOrder, refreshInterval) - newUrl := fmt.Sprintf("http://%s%s%s", + newUrl := fmt.Sprintf("http://%s%s%s%s", r.Host, + Prefix, preparePath(filePath), queryParams, ) @@ -205,7 +208,7 @@ func serveMedia(paths []string, regexes *regexes, formats *types.Types) httprout sortOrder := sortOrder(r) - path := strings.TrimPrefix(r.URL.Path, mediaPrefix) + path := strings.TrimPrefix(strings.TrimPrefix(r.URL.Path, Prefix), mediaPrefix) if runtime.GOOS == "windows" { path = strings.TrimPrefix(path, "/") @@ -240,7 +243,7 @@ func serveMedia(paths []string, regexes *regexes, formats *types.Types) httprout return } - fileUri := generateFileUri(path) + fileUri := Prefix + "/" + generateFileUri(path) fileName := filepath.Base(path) @@ -248,20 +251,20 @@ func serveMedia(paths []string, regexes *regexes, formats *types.Types) httprout refreshTimer, refreshInterval := refreshInterval(r) - queryParams := generateQueryParams(filters, sortOrder, refreshInterval) + rootUrl := Prefix + "/" + generateQueryParams(filters, sortOrder, refreshInterval) var htmlBody strings.Builder htmlBody.WriteString(``) htmlBody.WriteString(faviconHtml) htmlBody.WriteString(fmt.Sprintf(``, fileType.Css())) - htmlBody.WriteString((fileType.Title(queryParams, fileUri, path, fileName, mimeType))) + htmlBody.WriteString((fileType.Title(rootUrl, fileUri, path, fileName, Prefix, mimeType))) htmlBody.WriteString(``) if refreshInterval != "0ms" { - htmlBody.WriteString(fmt.Sprintf("", - queryParams, + htmlBody.WriteString(fmt.Sprintf("", + rootUrl, refreshTimer)) } - htmlBody.WriteString((fileType.Body(queryParams, fileUri, path, fileName, mimeType))) + htmlBody.WriteString((fileType.Body(rootUrl, fileUri, path, fileName, Prefix, mimeType))) htmlBody.WriteString(``) _, err = io.WriteString(w, gohtml.Format(htmlBody.String())) @@ -285,6 +288,25 @@ func serveVersion() httprouter.Handle { } } +func register(mux *httprouter.Router, path string, handle httprouter.Handle) { + mux.GET(path, handle) + + if Handlers { + fmt.Printf("Registered handler for path %s\n", path) + } +} + +func redirectRoot() httprouter.Handle { + return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { + newUrl := fmt.Sprintf("http://%s%s", + r.Host, + Prefix, + ) + + http.Redirect(w, r, newUrl, RedirectStatusCode) + } +} + func ServePage(args []string) error { timeZone := os.Getenv("TZ") if timeZone != "" { @@ -363,17 +385,23 @@ func ServePage(args []string) error { mux.PanicHandler = serverErrorHandler() - mux.GET("/", serveRoot(paths, regexes, cache, formats)) + Prefix = strings.TrimSuffix(Prefix, "/") - mux.GET("/favicons/*favicon", serveFavicons()) + register(mux, Prefix+"/", serveRoot(paths, regexes, cache, formats)) - mux.GET("/favicon.ico", serveFavicons()) + if Prefix != "" { + register(mux, "/", redirectRoot()) + } - mux.GET(mediaPrefix+"/*media", serveMedia(paths, regexes, formats)) + register(mux, Prefix+"/favicons/*favicon", serveFavicons()) - mux.GET(sourcePrefix+"/*static", serveStaticFile(paths, cache)) + register(mux, Prefix+"/favicon.ico", serveFavicons()) - mux.GET("/version", serveVersion()) + register(mux, Prefix+mediaPrefix+"/*media", serveMedia(paths, regexes, formats)) + + register(mux, Prefix+sourcePrefix+"/*static", serveStaticFile(paths, cache)) + + register(mux, Prefix+"/version", serveVersion()) if Cache { registerCacheHandlers(mux, args, cache, formats) diff --git a/types/audio/audio.go b/types/audio/audio.go index 1f106de..dca72c6 100644 --- a/types/audio/audio.go +++ b/types/audio/audio.go @@ -22,13 +22,13 @@ func (t Format) Css() string { return css.String() } -func (t Format) Title(queryParams, fileUri, filePath, fileName, mime string) string { +func (t Format) Title(rootUrl, fileUri, filePath, fileName, prefix, mime string) string { return fmt.Sprintf(`%s`, fileName) } -func (t Format) Body(queryParams, fileUri, filePath, fileName, mime string) string { - return fmt.Sprintf(``, - queryParams, +func (t Format) Body(rootUrl, fileUri, filePath, fileName, prefix, mime string) string { + return fmt.Sprintf(``, + rootUrl, fileUri, mime, fileName) diff --git a/types/flash/flash.go b/types/flash/flash.go index 6c18678..f42bd33 100644 --- a/types/flash/flash.go +++ b/types/flash/flash.go @@ -22,15 +22,15 @@ func (t Format) Css() string { return css.String() } -func (t Format) Title(queryParams, fileUri, filePath, fileName, mime string) string { +func (t Format) Title(rootUrl, fileUri, filePath, fileName, prefix, mime string) string { return fmt.Sprintf(`%s`, fileName) } -func (t Format) Body(queryParams, fileUri, filePath, fileName, mime string) string { +func (t Format) Body(rootUrl, fileUri, filePath, fileName, prefix, mime string) string { var html strings.Builder html.WriteString(fmt.Sprintf(``, fileUri)) - html.WriteString(fmt.Sprintf(`
`, queryParams)) + html.WriteString(fmt.Sprintf(`
`, rootUrl)) return html.String() } diff --git a/types/images/images.go b/types/images/images.go index 4ba00e5..5e6e099 100644 --- a/types/images/images.go +++ b/types/images/images.go @@ -37,7 +37,7 @@ func (t Format) Css() string { return css.String() } -func (t Format) Title(queryParams, fileUri, filePath, fileName, mime string) string { +func (t Format) Title(rootUrl, fileUri, filePath, fileName, prefix, mime string) string { dimensions, err := ImageDimensions(filePath) if err != nil { fmt.Println(err) @@ -49,14 +49,14 @@ func (t Format) Title(queryParams, fileUri, filePath, fileName, mime string) str dimensions.height) } -func (t Format) Body(queryParams, fileUri, filePath, fileName, mime string) string { +func (t Format) Body(rootUrl, fileUri, filePath, fileName, prefix, mime string) string { dimensions, err := ImageDimensions(filePath) if err != nil { fmt.Println(err) } - return fmt.Sprintf(`Roulette selected: %s`, - queryParams, + return fmt.Sprintf(`Roulette selected: %s`, + rootUrl, fileUri, dimensions.width, dimensions.height, diff --git a/types/text/text.go b/types/text/text.go index fcac42d..8a16e7c 100644 --- a/types/text/text.go +++ b/types/text/text.go @@ -27,18 +27,18 @@ func (t Format) Css() string { return css.String() } -func (t Format) Title(queryParams, fileUri, filePath, fileName, mime string) string { +func (t Format) Title(rootUrl, fileUri, filePath, fileName, prefix, mime string) string { return fmt.Sprintf(`%s`, fileName) } -func (t Format) Body(queryParams, fileUri, filePath, fileName, mime string) string { +func (t Format) Body(rootUrl, fileUri, filePath, fileName, prefix, mime string) string { body, err := os.ReadFile(filePath) if err != nil { body = []byte{} } - return fmt.Sprintf(``, - queryParams, + return fmt.Sprintf(``, + rootUrl, body) } diff --git a/types/types.go b/types/types.go index 203c229..ae67c01 100644 --- a/types/types.go +++ b/types/types.go @@ -20,8 +20,8 @@ var SupportedFormats = &Types{ type Type interface { Css() string - Title(queryParams, fileUri, filePath, fileName, mime string) string - Body(queryParams, fileUri, filePath, fileName, mime string) string + Title(rootUrl, fileUri, filePath, fileName, prefix, mime string) string + Body(rootUrl, fileUri, filePath, fileName, prefix, mime string) string Extensions() map[string]string MimeTypes() []string Validate(filePath string) bool diff --git a/types/video/video.go b/types/video/video.go index 0e017f5..66f6eaa 100644 --- a/types/video/video.go +++ b/types/video/video.go @@ -24,13 +24,13 @@ func (t Format) Css() string { return css.String() } -func (t Format) Title(queryParams, fileUri, filePath, fileName, mime string) string { +func (t Format) Title(rootUrl, fileUri, filePath, fileName, prefix, mime string) string { return fmt.Sprintf(`%s`, fileName) } -func (t Format) Body(queryParams, fileUri, filePath, fileName, mime string) string { - return fmt.Sprintf(``, - queryParams, +func (t Format) Body(rootUrl, fileUri, filePath, fileName, prefix, mime string) string { + return fmt.Sprintf(``, + rootUrl, fileUri, mime, fileName)