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

Code before:
			browseTemplateContext: listing,
		}

		tpl, err := fsrv.makeBrowseTemplate(tplCtx)
		if err != nil {
			return fmt.Errorf("parsing browse template: %v", err)
		}
		if err := tpl.Execute(buf, tplCtx); err != nil {
			return caddyhttp.Error(http.StatusInternalServerError, err)
		}
		w.Header().Set("Content-Type", "text/html; charset=utf-8")
	}

	_, _ = buf.WriteTo(w)

	return nil
}

func (fsrv *FileServer) loadDirectoryContents(ctx context.Context, fileSystem fs.FS, dir fs.ReadDirFile, root, urlPath string, repl *caddy.Replacer) (*browseTemplateContext, error) {
	if fsrv.FileLimit != 0 {
		maxDirLimit = fsrv.FileLimit
	}
	files, err := dir.ReadDir(maxDirLimit)
	if err != nil && err != io.EOF {
		return nil, err
	}

	// user can presumably browse "up" to parent folder if path is longer than "/"
	canGoUp := len(urlPath) > 1

	return fsrv.directoryListing(ctx, fileSystem, files, canGoUp, root, urlPath, repl), nil
}

// browseApplyQueryParams applies query parameters to the listing.
// It mutates the listing and may set cookies.
func (fsrv *FileServer) browseApplyQueryParams(w http.ResponseWriter, r *http.Request, listing *browseTemplateContext) {
	var orderParam, sortParam string

	// The configs in Caddyfile have lower priority than Query params,
	// so put it at first.
	for idx, item := range fsrv.Browse.SortOptions {
		// Only `sort` & `order`, 2 params are allowed
		if idx >= 2 {
			break
		}
		switch item {
		case sortByName, sortByNameDirFirst, sortBySize, sortByTime:
			sortParam = item
		case sortOrderAsc, sortOrderDesc:
			orderParam = item
		}

Review comment (suggestion):
Don't set the value of a global variable like this. `file_server` may be loaded more than once with different config, so they would clobber eachother. Make sure to use a local variable here to grab the default value, then override it with the configured one if non-zero.

Code after:
				Req:        r,
				RespHeader: templates.WrappedHeader{Header: w.Header()},
			},
			browseTemplateContext: listing,
		}

		tpl, err := fsrv.makeBrowseTemplate(tplCtx)
		if err != nil {
			return fmt.Errorf("parsing browse template: %v", err)
		}
		if err := tpl.Execute(buf, tplCtx); err != nil {
			return caddyhttp.Error(http.StatusInternalServerError, err)
		}
		w.Header().Set("Content-Type", "text/html; charset=utf-8")
	}

	_, _ = buf.WriteTo(w)

	return nil
}

func (fsrv *FileServer) loadDirectoryContents(ctx context.Context, fileSystem fs.FS, dir fs.ReadDirFile, root, urlPath string, repl *caddy.Replacer) (*browseTemplateContext, error) {
	dirLimit := defaultDirEntryLimit
	if fsrv.Browse.FileLimit != 0 {
		dirLimit = fsrv.Browse.FileLimit
	}
	files, err := dir.ReadDir(dirLimit)
	if err != nil && err != io.EOF {
		return nil, err
	}

	// user can presumably browse "up" to parent folder if path is longer than "/"
	canGoUp := len(urlPath) > 1

	return fsrv.directoryListing(ctx, fileSystem, files, canGoUp, root, urlPath, repl), nil
}

// browseApplyQueryParams applies query parameters to the listing.
// It mutates the listing and may set cookies.
func (fsrv *FileServer) browseApplyQueryParams(w http.ResponseWriter, r *http.Request, listing *browseTemplateContext) {
	var orderParam, sortParam string

	// The configs in Caddyfile have lower priority than Query params,
	// so put it at first.
	for idx, item := range fsrv.Browse.SortOptions {
		// Only `sort` & `order`, 2 params are allowed
		if idx >= 2 {
			break
		}
		switch item {
		case sortByName, sortByNameDirFirst, sortBySize, sortByTime: