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(``,
- queryParams,
+ return fmt.Sprintf(``,
+ 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)