fileserver: Add file_limit option for browse (to be experimental) (#6648)

* Add file_limit option for file_server browse

* Move file_limit inside browse.

* add file_server_file_limit caddyfile adapt test.
This commit is contained in:
Atakan Yenel 2024-11-05 17:35:32 +01:00 committed by GitHub
parent 91e34139a1
commit cc23ad6402
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 62 additions and 2 deletions

View File

@ -0,0 +1,36 @@
:80
file_server {
browse {
file_limit 4000
}
}
----------
{
"apps": {
"http": {
"servers": {
"srv0": {
"listen": [
":80"
],
"routes": [
{
"handle": [
{
"browse": {
"file_limit": 4000
},
"handler": "file_server",
"hide": [
"./Caddyfile"
]
}
]
}
]
}
}
}
}
}

View File

@ -66,8 +66,15 @@ type Browse struct {
// - `sort size` will sort by size in ascending order // - `sort size` will sort by size in ascending order
// The first option must be `sort_by` and the second option must be `order` (if exists). // The first option must be `sort_by` and the second option must be `order` (if exists).
SortOptions []string `json:"sort,omitempty"` SortOptions []string `json:"sort,omitempty"`
// FileLimit limits the number of up to n DirEntry values in directory order.
FileLimit int `json:"file_limit,omitempty"`
} }
const (
defaultDirEntryLimit = 10000
)
func (fsrv *FileServer) serveBrowse(fileSystem fs.FS, root, dirPath string, w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { 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 { if c := fsrv.logger.Check(zapcore.DebugLevel, "browse enabled; listing directory contents"); c != nil {
c.Write(zap.String("path", dirPath), zap.String("root", root)) c.Write(zap.String("path", dirPath), zap.String("root", root))
@ -206,7 +213,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) { 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 := defaultDirEntryLimit
if fsrv.Browse.FileLimit != 0 {
dirLimit = fsrv.Browse.FileLimit
}
files, err := dir.ReadDir(dirLimit)
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
return nil, err return nil, err
} }

View File

@ -16,6 +16,7 @@ package fileserver
import ( import (
"path/filepath" "path/filepath"
"strconv"
"strings" "strings"
"github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2"
@ -129,6 +130,16 @@ func (fsrv *FileServer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.Errf("unknown sort option '%s'", dVal) return d.Errf("unknown sort option '%s'", dVal)
} }
} }
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])
if fsrv.Browse.FileLimit != 0 {
return d.Err("file_limit is already enabled")
}
fsrv.Browse.FileLimit = val
default: default:
return d.Errf("unknown subdirective '%s'", d.Val()) return d.Errf("unknown subdirective '%s'", d.Val())
} }

View File

@ -66,6 +66,7 @@ respond with a file listing.`,
cmd.Flags().BoolP("templates", "t", false, "Enable template rendering") cmd.Flags().BoolP("templates", "t", false, "Enable template rendering")
cmd.Flags().BoolP("access-log", "a", false, "Enable the access log") cmd.Flags().BoolP("access-log", "a", false, "Enable the access log")
cmd.Flags().BoolP("debug", "v", false, "Enable verbose debug logs") cmd.Flags().BoolP("debug", "v", false, "Enable verbose debug logs")
cmd.Flags().IntP("file-limit", "f", defaultDirEntryLimit, "Max directories to read")
cmd.Flags().BoolP("no-compress", "", false, "Disable Zstandard and Gzip compression") 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.Flags().StringSliceP("precompressed", "p", []string{}, "Specify precompression file extensions. Compression preference implied from flag order.")
cmd.RunE = caddycmd.WrapCommandFuncForCobra(cmdFileServer) cmd.RunE = caddycmd.WrapCommandFuncForCobra(cmdFileServer)
@ -91,6 +92,7 @@ func cmdFileServer(fs caddycmd.Flags) (int, error) {
browse := fs.Bool("browse") browse := fs.Bool("browse")
templates := fs.Bool("templates") templates := fs.Bool("templates")
accessLog := fs.Bool("access-log") accessLog := fs.Bool("access-log")
fileLimit := fs.Int("file-limit")
debug := fs.Bool("debug") debug := fs.Bool("debug")
revealSymlinks := fs.Bool("reveal-symlinks") revealSymlinks := fs.Bool("reveal-symlinks")
compress := !fs.Bool("no-compress") compress := !fs.Bool("no-compress")
@ -151,7 +153,7 @@ func cmdFileServer(fs caddycmd.Flags) (int, error) {
} }
if browse { if browse {
handler.Browse = &Browse{RevealSymlinks: revealSymlinks} handler.Browse = &Browse{RevealSymlinks: revealSymlinks, FileLimit: fileLimit}
} }
handlers = append(handlers, caddyconfig.JSONModuleObject(handler, "handler", "file_server", nil)) handlers = append(handlers, caddyconfig.JSONModuleObject(handler, "handler", "file_server", nil))