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

Code before:
	"strings"
	"sync"
	"text/template"

	"go.uber.org/zap"

	"github.com/caddyserver/caddy/v2"
	"github.com/caddyserver/caddy/v2/modules/caddyhttp"
	"github.com/caddyserver/caddy/v2/modules/caddyhttp/templates"
)

// BrowseTemplate is the default template document to use for
// file listings. By default, its default value is an embedded
// document. You can override this value at program start, or
// if you are running Caddy via config, you can specify a
// custom template_file in the browse configuration.
//
//go:embed browse.html
var BrowseTemplate string

// 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.
	RevealSymlink bool `json:"reveal_symlink,omitempty"`
}

func (fsrv *FileServer) serveBrowse(root, dirPath string, w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
	fsrv.logger.Debug("browse enabled; listing directory contents",
		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)

Review comment (suggestion):
```suggestion
	RevealSymlinks bool `json:"reveal_symlinks,omitempty"`
```

Wondering if plural makes more sense :thinking:

Code after:
	"path"
	"strings"
	"sync"
	"text/template"

	"go.uber.org/zap"

	"github.com/caddyserver/caddy/v2"
	"github.com/caddyserver/caddy/v2/modules/caddyhttp"
	"github.com/caddyserver/caddy/v2/modules/caddyhttp/templates"
)

// BrowseTemplate is the default template document to use for
// file listings. By default, its default value is an embedded
// document. You can override this value at program start, or
// if you are running Caddy via config, you can specify a
// custom template_file in the browse configuration.
//
//go:embed browse.html
var BrowseTemplate string

// 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"`
}

func (fsrv *FileServer) serveBrowse(fileSystem fs.FS, root, dirPath string, w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
	fsrv.logger.Debug("browse enabled; listing directory contents",
		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.