diff --git a/modules/caddyhttp/fileserver/browse.go b/modules/caddyhttp/fileserver/browse.go index a19b4e17a856..e0f679322cdb 100644 --- a/modules/caddyhttp/fileserver/browse.go +++ b/modules/caddyhttp/fileserver/browse.go @@ -68,6 +68,10 @@ type Browse struct { SortOptions []string `json:"sort,omitempty"` } +const ( + defaultMaxDirLimit = 10000 +) + func (fsrv *FileServer) serveBrowse(fileSystem fs.FS, root, dirPath string, w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { if c := fsrv.logger.Check(zapcore.DebugLevel, "browse enabled; listing directory contents"); c != nil { c.Write(zap.String("path", dirPath), zap.String("root", root)) @@ -206,7 +210,11 @@ func (fsrv *FileServer) serveBrowse(fileSystem fs.FS, root, dirPath string, w ht } func (fsrv *FileServer) loadDirectoryContents(ctx context.Context, fileSystem fs.FS, dir fs.ReadDirFile, root, urlPath string, repl *caddy.Replacer) (*browseTemplateContext, error) { - files, err := dir.ReadDir(10000) // TODO: this limit should probably be configurable + dirLimit := defaultMaxDirLimit + if fsrv.FileLimit != 0 { + dirLimit = fsrv.FileLimit + } + files, err := dir.ReadDir(dirLimit) if err != nil && err != io.EOF { return nil, err } diff --git a/modules/caddyhttp/fileserver/caddyfile.go b/modules/caddyhttp/fileserver/caddyfile.go index 71b7638e477f..92b99daffc62 100644 --- a/modules/caddyhttp/fileserver/caddyfile.go +++ b/modules/caddyhttp/fileserver/caddyfile.go @@ -16,6 +16,7 @@ package fileserver import ( "path/filepath" + "strconv" "strings" "github.com/caddyserver/caddy/v2" @@ -58,6 +59,7 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) // browse [] // precompressed // status +// file_limit // disable_canonical_uris // } // @@ -168,6 +170,14 @@ func (fsrv *FileServer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { falseBool := false fsrv.CanonicalURIs = &falseBool + case "file_limit": + fileLimit := d.RemainingArgs() + if len(fileLimit) != 1 { + return d.Err("file_limit should have an integer value") + } + val, _ := strconv.Atoi(fileLimit[0]) + fsrv.FileLimit = val + case "pass_thru": if d.NextArg() { return d.ArgErr() diff --git a/modules/caddyhttp/fileserver/command.go b/modules/caddyhttp/fileserver/command.go index a76998405d31..e0cf14aab1d9 100644 --- a/modules/caddyhttp/fileserver/command.go +++ b/modules/caddyhttp/fileserver/command.go @@ -66,6 +66,7 @@ respond with a file listing.`, cmd.Flags().BoolP("templates", "t", false, "Enable template rendering") cmd.Flags().BoolP("access-log", "a", false, "Enable the access log") cmd.Flags().BoolP("debug", "v", false, "Enable verbose debug logs") + cmd.Flags().IntP("file-limit", "f", defaultMaxDirLimit, "Max directories to read") cmd.Flags().BoolP("no-compress", "", false, "Disable Zstandard and Gzip compression") cmd.Flags().StringSliceP("precompressed", "p", []string{}, "Specify precompression file extensions. Compression preference implied from flag order.") cmd.RunE = caddycmd.WrapCommandFuncForCobra(cmdFileServer) @@ -91,6 +92,7 @@ func cmdFileServer(fs caddycmd.Flags) (int, error) { browse := fs.Bool("browse") templates := fs.Bool("templates") accessLog := fs.Bool("access-log") + fileLimit := fs.Int("file-limit") debug := fs.Bool("debug") revealSymlinks := fs.Bool("reveal-symlinks") compress := !fs.Bool("no-compress") @@ -125,7 +127,7 @@ func cmdFileServer(fs caddycmd.Flags) (int, error) { handlers = append(handlers, caddyconfig.JSONModuleObject(handler, "handler", "templates", nil)) } - handler := FileServer{Root: root} + handler := FileServer{Root: root, FileLimit: fileLimit} if len(precompressed) != 0 { // logic mirrors modules/caddyhttp/fileserver/caddyfile.go case "precompressed" diff --git a/modules/caddyhttp/fileserver/staticfiles.go b/modules/caddyhttp/fileserver/staticfiles.go index 4ae69b647611..6a9430d4c584 100644 --- a/modules/caddyhttp/fileserver/staticfiles.go +++ b/modules/caddyhttp/fileserver/staticfiles.go @@ -172,6 +172,9 @@ type FileServer struct { fsmap caddy.FileSystems logger *zap.Logger + + // FileLimit limits the number of up to n DirEntry values in directory order. + FileLimit int `json:"file_limit,omitempty"` } // CaddyModule returns the Caddy module information.