Repository: caddyserver/caddy
File: modules/caddyhttp/fileserver/browse.go (Go)

Code before:

// Browse configures directory browsing.
type Browse struct {
	// Filename of the template to use instead of the embedded browse template.
	TemplateFile string `json:"template_file,omitempty"`

	// Determines whether or not targets of symlinks should be revealed.
	RevealSymlinks bool `json:"reveal_symlinks,omitempty"`

	// Override the default sort.
	// It includes the following options:
	//   - sort_by: name(default), namedirfirst, size, time
	//   - order: asc(default), desc
	// eg.:
	//   - `sort time desc` will sort by time in descending 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).
	SortOptions []string `json:"sort,omitempty"`
}

var (
	maxDirLimit = 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))
	}

	// Navigation on the client-side gets messed up if the
	// URL doesn't end in a trailing slash because hrefs to
	// "b/c" at path "/a" end up going to "/b/c" instead
	// of "/a/b/c" - so we have to redirect in this case
	// so that the path is "/a/" and the client constructs
	// relative hrefs "b/c" to be "/a/b/c".
	//
	// Only redirect if the last element of the path (the filename) was not
	// rewritten; if the admin wanted to rewrite to the canonical path, they
	// would have, and we have to be very careful not to introduce unwanted
	// redirects and especially redirect loops! (Redirecting using the
	// original URI is necessary because that's the URI the browser knows,
	// we don't want to redirect from internally-rewritten URIs.)
	// See https://github.com/caddyserver/caddy/issues/4205.
	// We also redirect if the path is empty, because this implies the path
	// prefix was fully stripped away by a `handle_path` handler for example.
	// See https://github.com/caddyserver/caddy/issues/4466.
	origReq := r.Context().Value(caddyhttp.OriginalRequestCtxKey).(http.Request)
	if r.URL.Path == "" || path.Base(origReq.URL.Path) == path.Base(r.URL.Path) {
		if !strings.HasSuffix(origReq.URL.Path, "/") {
			if c := fsrv.logger.Check(zapcore.DebugLevel, "redirecting to trailing slash to preserve hrefs"); c != nil {
				c.Write(zap.String("request_path", r.URL.Path))

Review comment (suggestion):
This should be a constant, not a variable. Should have a prefix like `default`

Code after:

// Browse configures directory browsing.
type Browse struct {
	// Filename of the template to use instead of the embedded browse template.
	TemplateFile string `json:"template_file,omitempty"`

	// Determines whether or not targets of symlinks should be revealed.
	RevealSymlinks bool `json:"reveal_symlinks,omitempty"`

	// Override the default sort.
	// It includes the following options:
	//   - sort_by: name(default), namedirfirst, size, time
	//   - order: asc(default), desc
	// eg.:
	//   - `sort time desc` will sort by time in descending 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).
	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 {
	if c := fsrv.logger.Check(zapcore.DebugLevel, "browse enabled; listing directory contents"); c != nil {
		c.Write(zap.String("path", dirPath), zap.String("root", root))
	}

	// Navigation on the client-side gets messed up if the
	// URL doesn't end in a trailing slash because hrefs to
	// "b/c" at path "/a" end up going to "/b/c" instead
	// of "/a/b/c" - so we have to redirect in this case
	// so that the path is "/a/" and the client constructs
	// relative hrefs "b/c" to be "/a/b/c".
	//
	// Only redirect if the last element of the path (the filename) was not
	// rewritten; if the admin wanted to rewrite to the canonical path, they
	// would have, and we have to be very careful not to introduce unwanted
	// redirects and especially redirect loops! (Redirecting using the
	// original URI is necessary because that's the URI the browser knows,
	// we don't want to redirect from internally-rewritten URIs.)
	// See https://github.com/caddyserver/caddy/issues/4205.
	// We also redirect if the path is empty, because this implies the path
	// prefix was fully stripped away by a `handle_path` handler for example.
	// See https://github.com/caddyserver/caddy/issues/4466.
	origReq := r.Context().Value(caddyhttp.OriginalRequestCtxKey).(http.Request)
	if r.URL.Path == "" || path.Base(origReq.URL.Path) == path.Base(r.URL.Path) {