From c555e95366cf1b833dc2af46c27e066c35994abf Mon Sep 17 00:00:00 2001 From: Mateusz Gajewski Date: Sat, 17 Dec 2016 19:30:08 +0100 Subject: [PATCH] Fix for issue #1287 - don't list hidden files in directory listing (#1290) * Fix for issue #1287 - hide hidden files * Reuse IsHidden * Fix failing tests --- caddyhttp/browse/browse.go | 40 ++++++++++++-------- caddyhttp/browse/browse_test.go | 18 ++++++--- caddyhttp/browse/setup.go | 7 +++- caddyhttp/browse/testdata/photos/hidden.html | 1 + caddyhttp/staticfiles/fileserver.go | 6 +-- 5 files changed, 48 insertions(+), 24 deletions(-) create mode 100644 caddyhttp/browse/testdata/photos/hidden.html diff --git a/caddyhttp/browse/browse.go b/caddyhttp/browse/browse.go index 24ef8d76..ce5b58af 100644 --- a/caddyhttp/browse/browse.go +++ b/caddyhttp/browse/browse.go @@ -20,6 +20,12 @@ import ( "github.com/mholt/caddy/caddyhttp/staticfiles" ) +const ( + sortByName = "name" + sortBySize = "size" + sortByTime = "time" +) + // Browse is an http.Handler that can show a file listing when // directories in the given paths are specified. type Browse struct { @@ -31,7 +37,7 @@ type Browse struct { // Config is a configuration for browsing in a particular path. type Config struct { PathScope string - Root http.FileSystem + Fs staticfiles.FileServer Variables interface{} Template *template.Template } @@ -161,11 +167,11 @@ func (l Listing) applySort() { // Check '.Order' to know how to sort if l.Order == "desc" { switch l.Sort { - case "name": + case sortByName: sort.Sort(sort.Reverse(byName(l))) - case "size": + case sortBySize: sort.Sort(sort.Reverse(bySize(l))) - case "time": + case sortByTime: sort.Sort(sort.Reverse(byTime(l))) default: // If not one of the above, do nothing @@ -173,11 +179,11 @@ func (l Listing) applySort() { } } else { // If we had more Orderings we could add them here switch l.Sort { - case "name": + case sortByName: sort.Sort(byName(l)) - case "size": + case sortBySize: sort.Sort(bySize(l)) - case "time": + case sortByTime: sort.Sort(byTime(l)) default: // If not one of the above, do nothing @@ -186,7 +192,7 @@ func (l Listing) applySort() { } } -func directoryListing(files []os.FileInfo, canGoUp bool, urlPath string) (Listing, bool) { +func directoryListing(files []os.FileInfo, canGoUp bool, urlPath string, config *Config) (Listing, bool) { var ( fileinfos []FileInfo dirCount, fileCount int @@ -212,6 +218,10 @@ func directoryListing(files []os.FileInfo, canGoUp bool, urlPath string) (Listin url := url.URL{Path: "./" + name} // prepend with "./" to fix paths with ':' in the name + if config.Fs.IsHidden(f) { + continue + } + fileinfos = append(fileinfos, FileInfo{ IsDir: f.IsDir(), Name: f.Name(), @@ -247,7 +257,7 @@ func (b Browse) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { inScope: // Browse works on existing directories; delegate everything else - requestedFilepath, err := bc.Root.Open(r.URL.Path) + requestedFilepath, err := bc.Fs.Root.Open(r.URL.Path) if err != nil { switch { case os.IsPermission(err): @@ -295,7 +305,7 @@ inScope: return b.ServeListing(w, r, requestedFilepath, bc) } -func (b Browse) loadDirectoryContents(requestedFilepath http.File, urlPath string) (*Listing, bool, error) { +func (b Browse) loadDirectoryContents(requestedFilepath http.File, urlPath string, config *Config) (*Listing, bool, error) { files, err := requestedFilepath.Readdir(-1) if err != nil { return nil, false, err @@ -312,7 +322,7 @@ func (b Browse) loadDirectoryContents(requestedFilepath http.File, urlPath strin } // Assemble listing of directory contents - listing, hasIndex := directoryListing(files, canGoUp, urlPath) + listing, hasIndex := directoryListing(files, canGoUp, urlPath, config) return &listing, hasIndex, nil } @@ -327,11 +337,11 @@ func (b Browse) handleSortOrder(w http.ResponseWriter, r *http.Request, scope st // If the query 'sort' or 'order' is empty, use defaults or any values previously saved in Cookies switch sort { case "": - sort = "name" + sort = sortByName if sortCookie, sortErr := r.Cookie("sort"); sortErr == nil { sort = sortCookie.Value } - case "name", "size", "type": + case sortByName, sortBySize, sortByTime: http.SetCookie(w, &http.Cookie{Name: "sort", Value: sort, Path: scope, Secure: r.TLS != nil}) } @@ -357,7 +367,7 @@ func (b Browse) handleSortOrder(w http.ResponseWriter, r *http.Request, scope st // ServeListing returns a formatted view of 'requestedFilepath' contents'. func (b Browse) ServeListing(w http.ResponseWriter, r *http.Request, requestedFilepath http.File, bc *Config) (int, error) { - listing, containsIndex, err := b.loadDirectoryContents(requestedFilepath, r.URL.Path) + listing, containsIndex, err := b.loadDirectoryContents(requestedFilepath, r.URL.Path, bc) if err != nil { switch { case os.IsPermission(err): @@ -372,7 +382,7 @@ func (b Browse) ServeListing(w http.ResponseWriter, r *http.Request, requestedFi return b.Next.ServeHTTP(w, r) } listing.Context = httpserver.Context{ - Root: bc.Root, + Root: bc.Fs.Root, Req: r, URL: r.URL, } diff --git a/caddyhttp/browse/browse_test.go b/caddyhttp/browse/browse_test.go index 08eebe27..c3f945c9 100644 --- a/caddyhttp/browse/browse_test.go +++ b/caddyhttp/browse/browse_test.go @@ -13,6 +13,7 @@ import ( "time" "github.com/mholt/caddy/caddyhttp/httpserver" + "github.com/mholt/caddy/caddyhttp/staticfiles" ) func TestSort(t *testing.T) { @@ -106,8 +107,10 @@ func TestBrowseHTTPMethods(t *testing.T) { Configs: []Config{ { PathScope: "/photos", - Root: http.Dir("./testdata"), - Template: tmpl, + Fs: staticfiles.FileServer{ + Root: http.Dir("./testdata"), + }, + Template: tmpl, }, }, } @@ -145,8 +148,11 @@ func TestBrowseTemplate(t *testing.T) { Configs: []Config{ { PathScope: "/photos", - Root: http.Dir("./testdata"), - Template: tmpl, + Fs: staticfiles.FileServer{ + Root: http.Dir("./testdata"), + Hide: []string{"photos/hidden.html"}, + }, + Template: tmpl, }, }, } @@ -199,7 +205,9 @@ func TestBrowseJson(t *testing.T) { Configs: []Config{ { PathScope: "/photos/", - Root: http.Dir("./testdata"), + Fs: staticfiles.FileServer{ + Root: http.Dir("./testdata"), + }, }, }, } diff --git a/caddyhttp/browse/setup.go b/caddyhttp/browse/setup.go index 29091542..813fde06 100644 --- a/caddyhttp/browse/setup.go +++ b/caddyhttp/browse/setup.go @@ -8,6 +8,7 @@ import ( "github.com/mholt/caddy" "github.com/mholt/caddy/caddyhttp/httpserver" + "github.com/mholt/caddy/caddyhttp/staticfiles" ) func init() { @@ -61,7 +62,11 @@ func browseParse(c *caddy.Controller) ([]Config, error) { } else { bc.PathScope = "/" } - bc.Root = http.Dir(cfg.Root) + + bc.Fs = staticfiles.FileServer{ + Root: http.Dir(cfg.Root), + Hide: httpserver.GetConfig(c).HiddenFiles, + } // Second argument would be the template file to use var tplText string diff --git a/caddyhttp/browse/testdata/photos/hidden.html b/caddyhttp/browse/testdata/photos/hidden.html new file mode 100644 index 00000000..e0f5c6c2 --- /dev/null +++ b/caddyhttp/browse/testdata/photos/hidden.html @@ -0,0 +1 @@ +Should be hidden diff --git a/caddyhttp/staticfiles/fileserver.go b/caddyhttp/staticfiles/fileserver.go index 41fe2d49..7c0caa52 100644 --- a/caddyhttp/staticfiles/fileserver.go +++ b/caddyhttp/staticfiles/fileserver.go @@ -117,7 +117,7 @@ func (fs FileServer) serveFile(w http.ResponseWriter, r *http.Request, name stri return http.StatusNotFound, nil } - if fs.isHidden(d) { + if fs.IsHidden(d) { return http.StatusNotFound, nil } @@ -132,8 +132,8 @@ func (fs FileServer) serveFile(w http.ResponseWriter, r *http.Request, name stri return http.StatusOK, nil } -// isHidden checks if file with FileInfo d is on hide list. -func (fs FileServer) isHidden(d os.FileInfo) bool { +// IsHidden checks if file with FileInfo d is on hide list. +func (fs FileServer) IsHidden(d os.FileInfo) bool { // If the file is supposed to be hidden, return a 404 for _, hiddenPath := range fs.Hide { // Check if the served file is exactly the hidden file.